// Constrain T to have a length property function getLength<T extends { length: number }>(item: T): number { return item.length; }
getLength('hello'); // OK: string has length getLength([1, 2, 3]); // OK: array has length // getLength(42); // Error: number doesn't have length
// Constrain with keyof function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; }
const user = { name: 'Alice', age: 25 }; const name = getProperty(user, 'name'); // string const age = getProperty(user, 'age'); // number // getProperty(user, 'email'); // Error: 'email' is not in keyof typeof user
graph TD
A["ToArray<string | number>"] --> B[分布式展开]
B --> C["ToArray<string>"]
B --> D["ToArray<number>"]
C --> E["string[]"]
D --> F["number[]"]
E --> G["string[] | number[]"]
F --> G
style A fill:#3178c6,color:#fff
style G fill:#2ecc71,color:#fff
// Exclude null and undefined typeNonNullable<T> = T extendsnull | undefined ? never : T; typeCleaned = NonNullable<string | null | undefined>; // string
// Extract from union typeExtract<T, U> = T extends U ? T : never; typeStrings = Extract<string | number | boolean, string | boolean>; // string | boolean
// Filter function overloads typeFunctionPropertyNames<T> = { [K in keyof T]: T[K] extendsFunction ? K : never; }[keyof T];
// Infer Promise value typeAwaited<T> = T extendsPromise<infer U> ? U extendsPromise<any> ? Awaited<U> // Recursive unwrap : U : T;
typeA1 = Awaited<Promise<string>>; // string typeA2 = Awaited<Promise<Promise<number>>>; // number
infer 的高级用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// Infer first and rest of tuple typeFirst<T extendsany[]> = T extends [infer F, ...any[]] ? F : never; typeRest<T extendsany[]> = T extends [any, ...infer R] ? R : never;
type F = First<[1, 2, 3]>; // 1 type R = Rest<[1, 2, 3]>; // [2, 3]
graph LR
A[Source Type T] --> B["映射 [K in keyof T]"]
B --> C{Key Remapping?}
C -->|as clause| D[转换 key 名称]
C -->|无| E[保持原 key]
D --> F[Value Transform]
E --> F
F --> G[New Mapped Type]
style A fill:#3178c6,color:#fff
style B fill:#9b59b6,color:#fff
style G fill:#2ecc71,color:#fff
graph TD
A[TypeScript 高级类型] --> B[泛型 Generics]
A --> C[条件类型 Conditional]
A --> D[映射类型 Mapped]
A --> E[模板字面量 Template Literal]
B --> B1[约束 extends]
B --> B2[默认类型参数]
B --> B3[泛型推断]
C --> C1[分布式条件类型]
C --> C2[infer 推断]
C --> C3[递归条件类型]
D --> D1[Key Remapping as]
D --> D2[修饰符 +/- readonly/?]
D --> D3[过滤键]
E --> E1[字符串操作类型]
E --> E2[联合类型叉积]
E --> E3[模式匹配]
style A fill:#3178c6,color:#fff
style B fill:#e74c3c,color:#fff
style C fill:#f39c12,color:#000
style D fill:#2ecc71,color:#fff
style E fill:#9b59b6,color:#fff
总结
TypeScript 的类型系统远不止 interface 和
type 别名。通过泛型约束、条件类型、infer
推断、映射类型和模板字面量类型的组合使用,可以构建出极其精确和灵活的类型定义。建议在实际项目中循序渐进地应用这些技巧:从简单的泛型函数开始,逐步过渡到条件类型和映射类型,最终能够设计出类型安全的
API。记住,类型编程的目的是为开发者服务——如果类型过于复杂导致可读性下降,适当简化也是明智的选择。