第 2 章:基础类型
学习目标
- 掌握 number / string / boolean / null / undefined
- 理解数组与元组的区别
- 区分 any / unknown / void / never
- 避开类型声明的常见坑
一、原始类型(Primitive)
typescript
let decimal: number = 6; // 十进制
let hex: number = 0xf00d; // 十六进制
let binary: number = 0b1010; // 二进制
let float: number = 3.14; // 浮点数
let negative: number = -1; // 负数
let nan: number = NaN; // 非数字
let infinity: number = Infinity; // 无穷大
let firstName: string = 'Tom';
let template: string = `Hello, ${firstName}`; // 模板字符串
let isActive: boolean = true;
let hasPermission: boolean = false;⚠️ 坑 1:
0.1 + 0.2 === 0.3是false(IEEE 754 浮点精度问题),TS 不会帮你修。
二、null 和 undefined
typescript
let nothing: null = null;
let notDefined: undefined = undefined;
// strictNullChecks 开启后:
let x: number = null; // ❌ Type 'null' is not assignable to type 'number'
let y: string = undefined; // ❌允许 null 的写法:
typescript
let nickname: string | null = 'Tom';
nickname = null; // ✅
let middleName: string | undefined = undefined;
middleName = 'Smith'; // ✅三、symbol 和 bigint
typescript
const KEY: symbol = Symbol('key');
const obj: Record<symbol, string> = { [KEY]: 'secret' };
console.log(obj[KEY]); // 'secret'
const huge: bigint = 9007199254740993n; // 大于 MAX_SAFE_INTEGER,必须加 n
const alsoBig: bigint = BigInt(100);⚠️ 坑 2:
number和bigint不能混算:1n + 1会编译报错,必须先转换类型。
四、数组(Array)
typescript
// 写法 1:类型 + []
let numbers: number[] = [1, 2, 3];
let names: string[] = ['Tom', 'Jerry'];
// 写法 2:泛型 Array<T>
let flags: Array<boolean> = [true, false];
// 数组方法自动推断类型
nums.push(4); // ✅
nums.push('5'); // ❌
nums.map(n => n * 2); // ✅ 推断 n: number只读数组:
typescript
const readonlyNums: readonly number[] = [1, 2, 3];
readonlyNums.push(4); // ❌ Property 'push' does not exist
readonlyNums[0] = 99; // ❌
readonlyNums.length; // ✅ 读可以五、元组(Tuple)
固定长度 + 类型的数组。
typescript
// 元组
let user: [string, number, string] = ['Tom', 18, 'tom@example.com'];
user[0]; // string
user[1]; // number
// 对比:用数组类型不够精确
let userArr: (string | number)[] = ['Tom', 18];
userArr[0].toUpperCase(); // ❌ 数组里是 string|number,不能直接调应用场景:
typescript
// 函数返回多个值
function getUser(): [string, number] {
return ['Tom', 18];
}
const [name, age] = getUser();
// key-value 对
const entries: [string, number][] = [
['Java', 1],
['TypeScript', 2],
];
// 可选元素
let optional: [string, number?] = ['Tom'];
// 剩余元素
let rest: [string, ...number[]] = ['Tom', 1, 2, 3, 4];⚠️ 坑 3:元组
push编译能过,但运行时破坏类型约束:point.push(3)不会报错,point[2]倒是会报"undefined"。
六、特殊类型
any(逃生舱)
typescript
let x: any = 'Tom';
x = 123;
x.foo.bar.baz; // ✅ 编译不报错,运行就崩unknown(类型安全的 any)
typescript
let value: unknown = 'Tom';
let s: string = value; // ❌ 不能直接赋值
if (typeof value === 'string') {
console.log(value.toUpperCase()); // ✅ 收窄后才能用
}void(无返回值)
typescript
function log(msg: string): void {
console.log(msg);
}
let result: void = log('hi'); // undefined 是 void 的子类型never(永不发生)
typescript
function throwError(msg: string): never {
throw new Error(msg);
}
function infiniteLoop(): never {
while (true) {}
}
// 穷尽性检查
type Status = 'success' | 'error';
function handle(s: Status): string {
switch (s) {
case 'success': return 'ok';
case 'error': return 'failed';
default:
const _: never = s; // 漏 case 编译报错
return _;
}
}七、any / unknown / never 对比
| 类型 | 含义 | 何时用 |
|---|---|---|
any | 任何类型 | 迁移期、JSON 解析、库无类型 |
unknown | 类型未知的"安全"版 | 解析外部数据(API、JSON) |
never | 永不发生 | 抛错、穷尽性检查 |
⚠️ 坑 4:
any是传染性的,函数返回any会让调用者全部丢失类型。优先用unknown。
八、对象类型
typescript
let user: { name: string; age: number } = {
name: 'Tom',
age: 18,
};
// 可选属性
let config: { host: string; port?: number } = { host: 'localhost' };
// 索引签名
let dict: { [key: string]: string } = {
name: 'Tom',
email: 'tom@example.com',
};九、本章小结
| 类型 | 例子 | 备注 |
|---|---|---|
| 原始 | number, string, boolean | 与 JS 一致 |
| 数组 | number[] / Array<number> | 类型一致 |
| 元组 | [string, number] | 固定长度和类型 |
| any | any | 逃生舱,慎用 |
| unknown | unknown | 安全的 any,需先收窄 |
| void | void | 函数无返回值 |
| never | never | 永不发生 |
动手练习
- 类型区分:写一个变量,可以是
string或null,但不能undefined - 元组应用:写函数返回
[number, string, boolean]元组 - unknown 实战:写
process(x: unknown),分别处理string/number/ 其他
下一章:第 3 章:变量与常量 →