TypeScript 基础类型速查
TS 基础类型 10 年没变,但 几个反直觉的细节 容易踩坑。
- 原始类型:boolean / number / string / bigint / symbol / null / undefined
- unknown > any:必须先 narrow 才能用,比 any 安全
- 三个长得像:
object/Object/{}是三种不同类型 void不只是 "无返回":也指代undefined这个值- Tuple 陷阱:长度不可越界,但
push()能扩
原始类型(一句话)
| 类型 | 说明 | 例子 |
|---|---|---|
boolean | 真假值 | true、false |
number | 整数和浮点 | 123、3.14 |
string | 字符串 | 'abc' |
bigint | 大整数 | 123n |
symbol | 唯一值 | Symbol('foo') |
null | 空值 | null |
undefined | 未定义 | undefined |
bigint 和 number 不能混算——1n + 1 会报错,要么 1n + 1n 要么 Number(1n) + 1。
strictNullChecks 2026 年默认开启,null / undefined 不再是其他类型的子类型。number | null | undefined 是显式标注,不是默认行为。
any vs unknown:现代推荐 unknown
any 完全绕过类型检查,unknown 必须先 narrow 才能用:
let a: any = 123;
a.toUpperCase(); // 编译通过,运行炸
let u: unknown = 123;
u.toUpperCase(); // 编译报错:Object is of type 'unknown'
能用 unknown 就别用 any。unknown 是"我不知道类型,但用之前必须先查清楚"的承诺。
unknown 的常见 narrow 方式:
function handle(value: unknown) {
if (typeof value === 'string') {
value.toUpperCase(); // OK,已 narrow 为 string
}
if (value instanceof Date) {
value.getTime(); // OK,已 narrow 为 Date
}
}
第三方库返回的 any、JSON 解析结果、用户输入——这些场景一律先标 unknown,再 narrow。
object vs Object vs
三个长得像但含义完全不同:
| 写法 | 含义 | 用途 |
|---|---|---|
object | 所有非原始类型(数组、对象、函数) | 新代码默认 |
Object | 所有 JS 对象的公共方法(toString、hasOwnProperty) | 几乎不用 |
{} | 空对象,但能访问 Object 上的方法 | 几乎不用 |
新代码只用 object 即可——Object 和 {} 都是历史包袱,会让 prettySure.toFixed() 这种属性访问报错(属性不在原型链上)。
let obj: object = { x: 1 };
obj.x; // Error:Property 'x' does not exist on type 'object'
obj['x']; // 同上
要访问具体属性,老老实实写对象字面量类型:
let obj: { x: number } = { x: 1 };
obj.x = 2; // OK
void:不是"无"而是 undefined
void 在 TS 里有两个含义:
- 函数返回值:函数不返回任何值
- 类型本身:只有
undefined(关闭strictNullChecks时也接受null)能赋值
function sayHi(): void {
console.log('Hi');
}
let v: void = undefined; // OK
let v2: void = sayHi(); // OK(sayHi 隐式返回 undefined)
void 不是"什么都没有"——它是 undefined 的类型别名。never 才是真正的"什么都没有"。
function throwErr(msg: string): never {
throw new Error(msg);
}
function loop(): never {
while (true) { /* ... */ }
}
never 用于"函数永远不返回"——要么抛错要么死循环。
Tuple 陷阱:长度不可越界,但 push() 能扩
let t: [number, string] = [1, 'a'];
t[2]; // Error:length 2 has no element at index 2
t.push(2); // 编译通过!运行时 t = [1, 'a', 2]
t[2]; // 还是 Error(TS 不知道你 push 了)
tuple 只在长度完全确定时用。否则用 [number, string] + 显式 length 检查,或者干脆 Array<number | string>。
带命名字段的 tuple 更易读:
type Point = [x: number, y: number];
type UserEntry = [id: string, name: string, createdAt: Date];
Array 两种写法
let a1: number[] = [1, 2, 3]; // 简写,常见
let a2: Array<number> = [1, 2, 3]; // 泛型写法
let a3: (number | string)[] = [1, 'a']; // 联合类型数组
写法 1 更简洁,写法 2 在复杂嵌套时更清晰(Array<Array<number>> 比 number[][] 易读)。
只读数组用 readonly:
const arr: readonly number[] = [1, 2, 3];
arr.push(4); // Error
Function 类型
参数和返回值分开标注:
function add(a: number, b: number): number {
return a + b;
}
// 可选参数和默认参数
function greet(name: string, greeting = 'Hello'): string {
return `${greeting}, ${name}`;
}
函数类型本身可以提取:
type Adder = (a: number, b: number) => number;
const add: Adder = (a, b) => a + b;
References
- TypeScript Handbook: Everyday Types —— 官方手册
- TypeScript: Object vs object vs - stackoverflow —— 三个类型的对比
- The object Type in TypeScript - Marius Schulz ——
object类型详解 - TypeScript: any vs unknown —— unknown 推荐用法的讨论