TypeScript高级类型系统:从泛型到条件类型的完全指南
深入讲解TypeScript的泛型、条件类型、映射类型和模板字面量类型,写出真正类型安全的代码
折
折腾侠
2026/03/19 发布
21约 6 分钟577 字 / 824 词00
引言
TypeScript的类型系统是其最强大的特性之一。许多开发者只停留在基础类型注解层面,没有充分利用TypeScript的高级特性。掌握泛型、条件类型、映射类型等高级特性,能让你的代码既有完整的类型安全,又不失灵活性。
一、泛型的高级用法
1.1 泛型约束
TypeScript
// 约束T必须有length属性
function getLength<T extends { length: number }>(arr: T): number {
return arr.length;
}
getLength([1, 2, 3]); // OK
getLength('hello'); // OK
getLength({ length: 5 }); // OK
getLength(42); // Error: number没有length属性
// keyof约束
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 28 };
getProperty(user, 'name'); // 返回类型是string
getProperty(user, 'age'); // 返回类型是number
getProperty(user, 'email'); // Error: 'email'不是user的键
1.2 条件类型
条件类型让类型系统具备了if-else的能力:
TypeScript
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;
type FnReturn = ReturnType<() => string>; // string
type FnReturn2 = ReturnType<() => Promise<number>>; // Promise<number>
// 提取Promise的值类型
type Awaited<T> = T extends Promise<infer V> ? Awaited<V> : T;
type Val = Awaited<Promise<Promise<string>>>; // string
1.3 分布式条件类型
当条件类型用于联合类型时,会自动分发:
TypeScript
type ToArray<T> = T extends any ? T[] : never;
// 分布式行为:string | number 分别应用
type Arr = ToArray<string | number>; // string[] | number[]
// 如果想避免分布,用元组包裹
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type Arr2 = ToArrayNonDist<string | number>; // (string | number)[]
二、映射类型
2.1 基础映射类型
TypeScript
// 将所有属性变为可选
type Partial<T> = {
[K in keyof T]?: T[K];
};
// 将所有属性变为只读
type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
// 将所有属性变为必填(去掉可选)
type Required<T> = {
[K in keyof T]-?: T[K]; // -? 移除可选修饰符
};
// 从T中选取指定属性
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
2.2 键重映射(as子句)
TypeScript
// 将所有属性名转为getter形式
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface User {
name: string;
age: number;
}
type UserGetters = Getters<User>;
// { getName: () => string; getAge: () => number; }
// 过滤属性:排除值类型为函数的属性
type NonFunctionProperties<T> = {
[K in keyof T as T[K] extends Function ? never : K]: T[K];
};
三、模板字面量类型
TypeScript
type EventName = 'click' | 'focus' | 'blur';
type Handler = `on${Capitalize<EventName>}`;
// 'onClick' | 'onFocus' | 'onBlur'
// 实用工具:从对象类型生成事件类型
type Events<T extends string> = {
[K in T as `on${Capitalize<K>}`]?: (event: Event) => void;
};
// CSS属性类型
type CSSUnit = 'px' | 'em' | 'rem' | '%';
type CSSValue = `${number}${CSSUnit}`;
// '100px' | '1.5em' 等
四、实用工具类型实现
4.1 DeepPartial
TypeScript
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
interface Config {
server: {
host: string;
port: number;
ssl: { cert: string; key: string };
};
database: { url: string };
}
// DeepPartial<Config> 所有嵌套属性都可选
function updateConfig(patch: DeepPartial<Config>) { ... }
4.2 路径类型(深度keyof)
TypeScript
type DeepKeys<T, Prefix extends string = ''> = {
[K in keyof T & string]: T[K] extends object
? DeepKeys<T[K], `${Prefix}${K}.`>
: `${Prefix}${K}`;
}[keyof T & string];
type UserKeys = DeepKeys<{
name: string;
address: { city: string; zip: string };
}>;
// 'name' | 'address.city' | 'address.zip'
4.3 函数重载类型
TypeScript
function process(x: string): string;
function process(x: number): number;
function process(x: string | number): string | number {
if (typeof x === 'string') return x.toUpperCase();
return x * 2;
}
// 或者用条件类型实现同样效果
type Process<T extends string | number> =
T extends string ? string : number;
declare function process2<T extends string | number>(x: T): Process<T>;
五、类型推断技巧
5.1 从数据推断类型(satisfies)
TypeScript
// satisfies:让值满足类型约束,同时保留最具体的类型
const routes = {
home: '/',
about: '/about',
user: (id: number) => `/user/${id}`,
} satisfies Record<string, string | ((id: number) => string)>;
// routes.home 的类型是 '/'(字面量类型),不是 string
// routes.user 的类型是 (id: number) => string
5.2 NoInfer(TypeScript 5.4+)
TypeScript
// 防止某个位置触发类型推断
function createState<T>(initial: T, fallback: NoInfer<T>): T {
return initial ?? fallback;
}
// T 只从 initial 推断,fallback 不影响推断
createState(1, 2); // T = number, OK
createState(1, 'two'); // Error: 'two'不是number类型
六、类型安全的设计模式
6.1 区分联合类型(Discriminated Union)
TypeScript
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E };
function fetchUser(id: string): Promise<Result<User>> {
try {
const user = await api.getUser(id);
return { success: true, data: user };
} catch (error) {
return { success: false, error: error as Error };
}
}
// 使用时TypeScript会自动缩窄类型
const result = await fetchUser('123');
if (result.success) {
console.log(result.data.name); // data的类型是User
} else {
console.error(result.error.message); // error的类型是Error
}
6.2 Builder模式的类型安全实现
TypeScript
type BuilderState = {
name: string;
age: number;
email: string;
};
class UserBuilder<State extends Partial<BuilderState> = {}> {
private state: State;
setName(name: string): UserBuilder<State & { name: string }> {
return new UserBuilder({ ...this.state, name });
}
setAge(age: number): UserBuilder<State & { age: number }> {
return new UserBuilder({ ...this.state, age });
}
// 只有name和age都设置后才能build
build(
this: UserBuilder<State & { name: string; age: number }>
): BuilderState {
return this.state as BuilderState;
}
}
结语
TypeScript的类型系统本质上是一门独立的图灵完备语言。深入理解这些高级特性,不仅能帮你写出类型安全的代码,更能让你设计出优雅的API——让调用者在写代码时得到精确的类型提示和编译期错误检查,大幅减少运行时Bug。