TypeScript 高级类型体操:条件类型与模板字面量深度剖析
TypeScript 不仅是一个带有静态类型的 JavaScript 超集,其类型系统本身就是一门图灵完备的纯函数式编程语言。
一、 分布式条件类型 (Distributive Conditional Types)
在条件类型中,如果泛型参数是裸类型参数(Naked Type Parameter),当传入联合类型时会自动展开为分布式计算:
typescript
type ToArray<Type> = Type extends any ? Type[] : never;
// 结果为: string[] | number[],而非 (string | number)[]
type StrOrNumArray = ToArray<string | number>;
若需阻止这一默认分布式行为,只需将参数用元组包裹:
typescript
type NonDistributive<Type> = [Type] extends [any] ? Type[] : never;
type MixedArray = NonDistributive<string | number>; // (string | number)[]
二、 infer 关键字的嵌套模式匹配
infer 允许我们在条件类型的 extends 子句中声明一个待推断的类型变量。
例如实现通用的 Promise 返回值深层解包:
typescript
type DeepAwaited<T> = T extends Promise<infer U> ? DeepAwaited<U> : T;
type Case1 = DeepAwaited<Promise<Promise<string>>>; // string
type Case2 = DeepAwaited<number>; // number
三、 模板字面量类型的实际业务场景
TypeScript 4.1 引入的模板字面量类型让我们可以直接在类型系统内部处理字符串格式转换,比如将驼峰命名转下划线命名:
typescript
type CamelToKebab<S extends string> = S extends `${infer C}${infer Rest}`
? C extends Lowercase<C>
? `${C}${CamelToKebab<Rest>}`
: `-${Lowercase<C>}${CamelToKebab<Rest>}`
: S;
type Res = CamelToKebab<'userInfoData'>; // "user-info-data"
四、 结语
类型体操的意义不仅在于炫技,更在于为大型复杂项目构建具有高健壮性、能够精确推导的 API 契约,让潜在的逻辑缺陷在编译期就被彻底消灭。