TypeScript 高级类型
TypeScript 中的条件类型、函数重载、可辨识联合、类型守卫、infer 和映射类型等高级类型能力。
#tech / dev
#resource / typescript
#type / concept
#status / growing
[!info] related notes
- 所属 MOC: TypeScript MOC
- 前置概念: TypeScript, TypeScript 速记
- 并列概念: TypeScript 中的 unknown 与 any
- 面试页: TS 常用工具类型有哪些,怎么用
TypeScript 高级类型
一句话定义
TypeScript 高级类型是泛型、条件类型、函数重载、可辨识联合、类型守卫、infer 和映射类型等能力的统称,它们让类型系统能表达更复杂的输入输出关系。
核心机制 / 工作原理
1. 泛型 Generics
在定义时不指定具体类型,使用时再确定。
function identity<T>(value: T): T {
return value;
}
const num = identity(42); // 推导为 number
const str = identity('hello'); // 推导为 string
泛型常用于封装返回值类型不确定的函数,如 Promise<Result<T>>。
2. 条件类型 Conditional Types
type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<string>; // 'yes'
type B = IsString<number>; // 'no'
配合 infer 可以提取类型:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
3. 函数重载 Function Overloads
当同一个函数根据参数类型返回不同结构时使用。
function parse(value: string): { type: 'text'; value: string };
function parse(value: number): { type: 'number'; value: number };
function parse(value: string | number) {
if (typeof value === 'string') {
return { type: 'text', value };
}
return { type: 'number', value };
}
const r1 = parse('hi'); // { type: 'text'; value: string }
const r2 = parse(42); // { type: 'number'; value: number }
4. 可辨识联合 Discriminated Union
用一个共同字段区分不同类型,配合类型守卫收窄。
type Shape =
| { kind: 'circle'; radius: number }
| { kind: 'rect'; width: number; height: number };
function area(s: Shape): number {
switch (s.kind) {
case 'circle': return Math.PI * s.radius ** 2;
case 'rect': return s.width * s.height;
}
}
5. 类型守卫 Type Guards
function isString(val: unknown): val is string {
return typeof val === 'string';
}
function example(val: string | number) {
if (isString(val)) {
val.toUpperCase(); // TS 知道这里是 string
}
}
内置守卫:typeof、instanceof、in、判空。
6. infer 关键字
在条件类型中声明一个待推导的类型变量。
type ElementType<T> = T extends (infer E)[] ? E : never;
type N = ElementType<number[]>; // number
7. 泛型约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
最小例子 / 最小场景
根据查询类型返回不同结构:
type QueryType = 'user' | 'order';
type QueryResult<T extends QueryType> =
T extends 'user' ? { id: string; name: string } :
T extends 'order' ? { id: string; amount: number } :
never;
function query<T extends QueryType>(type: T): QueryResult<T> {
if (type === 'user') {
return { id: 'u1', name: 'Arlon' } as QueryResult<T>;
}
return { id: 'o1', amount: 100 } as QueryResult<T>;
}
const user = query('user'); // { id: string; name: string }
const order = query('order'); // { id: string; amount: number }
边界与常见误解
as type断言不是类型安全的保障,是绕过类型系统的手段;应尽量用泛型和条件类型让 TS 自动推导- 函数重载的实现签名(最后一个签名)不对外可见,只用于内部实现
- 条件类型在分布式联合类型上会展开:
Foo<A | B>等于Foo<A> | Foo<B> infer只能在extends子句中使用