TypeScript 高级类型技巧
概述
TypeScript 的高级类型系统是其最强大的特性之一。本文深入探索 TypeScript 高级类型、条件类型、映射类型等高级特性,帮助你构建更健壮的类型定义。
条件类型
基本语法
typescript
type TypeA = SomeType extends OtherType ? TrueType : FalseType示例
typescript
type IsString<T> = T extends string ? true : false
type A = IsString<"hello"> // true
type B = IsString<123> // false分布式条件类型
typescript
type ToArray<T> = T extends any ? T[] : never
type A = ToArray<string> // string[]
type B = ToArray<number | string> // number[] | string[]条件类型推断
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type A = ReturnType<() => string> // string
type B = ReturnType<() => Promise<number>> // Promise<number>
type C = ReturnType<() => never> // never
type Parameters<T> = T extends (...args: infer P) => any ? P : never
type A = Parameters<(name: string, age: number) => void> // [string, number]映射类型
基本语法
typescript
type MappedType<T> = {
[K in keyof T]: T[K]
}只读和可选
typescript
type Readonly<T> = {
readonly [K in keyof T]: T[K]
}
type Partial<T> = {
[K in keyof T]?: T[K]
}
type Required<T> = {
[K in keyof T]-?: T[K]
}实践示例
typescript
interface User {
id: number
name: string
email: string
age: number
}
type ReadonlyUser = Readonly<User>
type PartialUser = Partial<User>
type UserPreview = Pick<User, 'id' | 'name'>
type UserUpdate = Partial<Pick<User, 'name' | 'email'>>键重新映射
typescript
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 }模板字面量类型
基本用法
typescript
type World = "world"
type Greeting = `hello ${World}` // "hello world"
type EmailLocaleIDs = "welcome-email" | "email-heading"
type FooterLocaleIDs = "footer-title" | "footer-sendoff"
type AllLocaleIDs = `${EmailLocaleIDs}_id` | `${FooterLocaleIDs}_id`
// "welcome-email_id" | "email-heading_id" | "footer-title_id" | "footer-sendoff_id"提取路径
typescript
type ExtractRouteParams<T extends string> =
T extends `${infer _Start}:${infer Param}/${infer Rest}`
? Param | ExtractRouteParams<`/${Rest}`>
: T extends `${infer _Start}:${infer Param}`
? Param
: never
type Params = ExtractRouteParams<'/users/:id/posts/:postId'>
// "id" | "postId"递归类型
深度只读
typescript
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}
interface Nested {
user: {
name: string
address: {
city: string
}
}
}
type DeepNested = DeepReadonly<Nested>
// 所有嵌套属性都变为 readonly深度可选
typescript
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K]
}展平类型
typescript
type Flatten<T> = T extends Array<infer U>
? U extends object
? Flatten<U>
: U
: T
type A = Flatten<string[]> // string
type B = Flatten<number[][]> // number
type C = Flatten<{ a: string }> // { a: string }infer 关键字
在条件类型中推断
typescript
// 推断函数返回类型
type UnpackPromise<T> = T extends Promise<infer U> ? U : T
type A = UnpackPromise<Promise<string>> // string
type B = UnpackPromise<Promise<number[]>> // number[]
// 推断构造函数
type ConstructorParameters<T extends new (...args: any) => any> =
T extends new (...args: infer P) => any ? P : never
class Person {
constructor(public name: string, public age: number) {}
}
type PersonParams = ConstructorParameters<typeof Person> // [string, number]工具类型扩展
自定义工具类型
typescript
// 排除 null 和 undefined
type NonNullable<T> = T extends null | undefined ? never : T
// 移除索引签名
type RemoveIndexSignature<T> = {
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K]
}
// 私有属性
type Public<T> = {
[K in keyof T as K extends `_${string}` ? never : K]: T[K]
}互斥属性
typescript
type Exclusive<T, U extends keyof T> = T & { [K in Exclude<keyof T, U>]?: never }
type User = {
name: string
email: string
}
type GuestUser = Exclusive<User, 'email'>
// { name: string; email: string; password?: never } | { name: string; email?: never }高级模式
链式调用类型
typescript
type Chainable<T = {}> = {
option<K extends string, V>(
key: K,
value: V
): Chainable<T & { [P in K]: V }>
get(): T
}
declare function chainable<T>(): Chainable<T>
const result = chainable()
.option('name', 'John')
.option('age', 30)
.get()
// result: { name: string; age: number }事件系统
typescript
type EventName<T extends string> = `on${Capitalize<T>}`
type EventHandlers<T extends string> = {
[K in EventName<T>]: (event: CustomEvent) => void
}
type ButtonEvents = EventHandlers<'click' | 'focus' | 'blur'>
// { onClick: (event: CustomEvent) => void; onFocus: ...; onBlur: ... }类型安全的 EventEmitter
typescript
type EventMap = {
user: { id: number; name: string }
post: { id: number; title: string }
comment: { id: number; content: string }
}
class TypedEventEmitter<Events extends Record<string, any>> {
on<K extends keyof Events>(event: K, listener: (data: Events[K]) => void): this {
// implementation
return this
}
emit<K extends keyof Events>(event: K, data: Events[K]): boolean {
// implementation
return true
}
}
const emitter = new TypedEventEmitter<EventMap>()
emitter.on('user', (data) => {
console.log(data.id, data.name) // 类型安全
})实用技巧
类型守卫组合
typescript
type isStringOrNumber<T> = T extends string ? 'string' : 'number'
type A = isStringOrNumber<string> // 'string'
type B = isStringOrNumber<number> // 'number'
type IsUnion<T, U = T> = T extends U
? [U] extends [T]
? false
: true
: false
type C = IsUnion<string | number> // true
type D = IsUnion<string> // falseVariance 标注
typescript
// 协变 (Covariance) - 返回类型
type Covariant<T> = () => T
// 逆变 (Contravariance) - 参数类型
type Contravariant<T> = (value: T) => void
// 不变 (Invariant) - 既做参数又做返回
type Invariant<T> = (value: T) => T避免类型膨胀
typescript
// 使用泛型约束
type Response<T> = {
data: T
status: number
message: string
}
// 使用映射类型
type AllResponses = {
[K in keyof typeof endpoints]: Response<(typeof endpoints)[K]>
}总结
掌握 TypeScript 高级类型能够:
- 构建更精确的类型定义
- 提高代码的类型安全性
- 提供更好的开发时类型提示
- 编写更灵活和可复用的代码
