TypeScript 05:交叉类型、索引签名、元组与 enum
有 JS 基础即可阅读。建议先读第 01~04 课。
1. 交叉类型 &:把多个类型「合体」
A & B 表示「同时满足 A 和 B」------和联合类型 |(满足其一)正好相反:
ts
interface Loggable {
log: () => string
}
interface Timestamped {
createdAt: number
}
type Entry = Loggable & Timestamped // 且:两个都得有
const e: Entry = {
log: () => '日志',
createdAt: 1728800000000,
}
最常用场景:给已有类型追加字段,不用改原类型:
ts
interface Person {
name: string
}
type Admin = Person & { level: number } // Person 的全部 + 新增 level
const admin: Admin = { name: 'Tom', level: 3 }
同名属性类型冲突时,结果是 never(谁也满足不了):{ a: string } & { a: number } 的 a 就是 never。
2. 索引签名:给「键不固定」的对象立规矩
键是动态的(字典类数据)时,没法逐字段列,用索引签名声明「任意键 → 固定值类型」:
ts
const scores: { [name: string]: number } = { math: 90, english: 85 }
两个要点:
- strict 下读取结果带
undefined(键是动态的,TS 不敢保证存在):
ts
const math = scores['math'] // number | undefined
math.toFixed(0) // ❌ Object is possibly 'undefined',先判断再用
- 声明后所有字段必须兼容它 :
{ [key: string]: string; version: number }不合法------version是 number,违反了「任意键都是 string」
Record<string, number> 是它的泛型等价写法。使用建议:能用具体字段就别用索引签名,它是检查强度最低的对象类型。
3. 元组 tuple:定长、定序的数组
数组 number[] 只约束「每个元素是 number」,不约束长度和位置;元组全部约束:
ts
const point: [number, number] = [3, 4] // 恰好两个,都是 number
const bad: [number, number] = [1, '2'] // ❌ 位置类型也要对上
标签元组:给位置起名,可读性大增------多返回值的标准答案:
ts
function divide(
numerator: number,
denominator: number,
): [quotient: number, remainder: number] {
return [Math.floor(numerator / denominator), numerator % denominator]
}
const [quotient, remainder] = divide(17, 5)
剩余元素:[name: string, ...points: number[]] = 第一个是名字,后面随便几个数字。
4. enum 与它的现代替代品
enum 是 TS 的私有语法------它会生成一个真实的运行时对象,而不是可剥掉的注解:
ts
enum Status {
Loading = 'loading',
Success = 'success',
}
console.log(Status.Success) // 'success'------运行时真有这个对象
这正是它的问题:第 01 课说过「TS = JS + 类型,注解运行前被剥掉」,而 enum 违反了这个规则 (在纯 JS 运行环境直接语法报错),还带来一堆历史坑。现代实践更推荐 as const 对象 + 联合类型:
ts
const STATUS = {
loading: 'loading',
success: 'success',
error: 'error',
} as const
type Status = (typeof STATUS)[keyof typeof STATUS] // 'loading' | 'success' | 'error'
读法:typeof STATUS 拿到对象的类型,keyof 拿到键的联合,索引访问取到「所有值」的联合------效果和 enum 一致,但全程可剥除、和普通对象一样用。
5. 高频报错速查
| 报错 | 人话 |
|---|---|
Property 'createdAt' is missing in type ... |
交叉类型要求字段全齐 |
Object is possibly 'undefined' |
索引签名读取后没判空 |
Index signature for type 'string' is missing ... |
对象字段类型与索引签名不兼容 |
Source has 3 element(s) but target allows only 2 |
元组长度超了 |
Type '"loaded"' is not assignable ... |
状态值不在 as const 联合里(多半拼错) |