TypeScript 高级类型体操
类型体操是什么
TypeScript 的类型系统是图灵完备的,这意味着你可以在类型层面实现复杂的逻辑运算。社区把这种高级类型编程戏称为”类型体操”。
常用工具类型实现
DeepReadonly
递归地将对象所有属性变为只读:
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? T[K] extends Function
? T[K]
: DeepReadonly<T[K]>
: T[K];
};
interface Config {
db: {
host: string;
port: number;
};
features: string[];
}
type ReadonlyConfig = DeepReadonly<Config>;
// 所有嵌套属性都变为 readonlyPathKeys
提取对象所有嵌套路径的联合类型:
type PathKeys<T, Prefix extends string = ""> = T extends object
? {
[K in keyof T & string]: T[K] extends object
? `${Prefix}${K}` | PathKeys<T[K], `${Prefix}${K}.`>
: `${Prefix}${K}`;
}[keyof T & string]
: never;
interface User {
name: string;
address: {
city: string;
zip: string;
};
}
type UserPaths = PathKeys<User>;
// "name" | "address" | "address.city" | "address.zip"条件类型与 infer
使用 infer 提取函数返回值中 Promise 的内部类型:
type UnwrapPromise<T> = T extends Promise<infer U>
? U extends Promise<any>
? UnwrapPromise<U>
: U
: T;
type A = UnwrapPromise<Promise<Promise<string>>>; // string
type B = UnwrapPromise<number>; // number模板字面量类型
TypeScript 4.1 引入的模板字面量类型非常强大:
type EventName<T extends string> = `on${Capitalize<T>}`;
type Events = EventName<"click" | "focus" | "blur">;
// "onClick" | "onFocus" | "onBlur"
type CSSProperty = `${string}-${string}`;
const valid: CSSProperty = "background-color"; // ✅实际应用场景
类型体操不只是炫技,在实际项目中有很多应用:
- API 类型安全 - 根据路由路径自动推导请求/响应类型
- 状态管理 - 确保 action 和 reducer 的类型匹配
- 表单验证 - 在类型层面约束表单字段和验证规则
掌握这些技巧能让你写出更安全、更具表达力的 TypeScript 代码。
