TypeScript 类型体操实用技巧
整理日常开发中遇到的 TypeScript 高级类型用法,让类型系统为你服务。
为什么要学类型体操
TypeScript 的类型系统是图灵完备的,虽然日常开发不需要写太复杂的类型,但掌握一些常用技巧可以:
- 减少
any的使用,提升代码安全性 - 让 IDE 提供更精准的智能提示
- 在编译期就发现潜在错误
泛型约束
泛型让我们编写可复用的类型,extends 关键字可以约束泛型的范围:
typescript
// 约束 T 必须有 length 属性
function logLength<T extends { length: number }>(value: T): void {
console.log(value.length)
}
logLength('hello') // ✅ 字符串有 length
logLength([1, 2, 3]) // ✅ 数组有 length
logLength(123) // ❌ 数字没有 length实际应用场景
typescript
// 从对象中安全地获取属性值
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
const user = { name: 'Alice', age: 25 }
getProperty(user, 'name') // ✅ 返回 string
getProperty(user, 'email') // ❌ 'email' 不存在于 user 类型条件类型
条件类型根据条件选择不同的类型,语法类似三元表达式:
typescript
type IsString<T> = T extends string ? 'yes' : 'no'
type A = IsString<string> // 'yes'
type B = IsString<number> // 'no'实用案例:提取函数返回类型
typescript
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
function getUser() {
return { name: 'Alice', age: 25 }
}
type User = ReturnType<typeof getUser>
// { name: string; age: number }映射类型
映射类型可以基于已有类型创建新类型:
typescript
// 将所有属性变为可选(内置的 Partial 就是这么实现的)
type MyPartial<T> = {
[K in keyof T]?: T[K]
}
// 将所有属性变为只读
type MyReadonly<T> = {
readonly [K in keyof T]: T[K]
}
// 实用:将对象所有属性变为字符串类型
type ToString<T> = {
[K in keyof T]: string
}工具类型实战
提取对象中的函数属性
typescript
type FunctionKeys<T> = {
[K in keyof T]: T[K] extends Function ? K : never
}[keyof T]
interface User {
name: string
greet(): void
age: number
farewell(): void
}
type Methods = FunctionKeys<User> // 'greet' | 'farewell'深度只读
typescript
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K]
}总结
类型体操不需要一次学完,建议在实际项目中遇到问题时逐步深入。最重要的原则:类型是为开发服务的,不要为了炫技而过度设计类型。