TypeScript类型体操进阶:掌握高级类型系统
深入探讨TypeScript高级类型系统,包括条件类型、映射类型、模板字面量类型等高级特性,助你写出类型安全的代码
TypeScript类型系统进阶#
TypeScript的类型系统非常强大,掌握高级类型特性可以帮助我们写出更安全、更优雅的代码。
条件类型#
基础条件类型#
1
2
3
4
5
6
7
8
9
10
| // 类似三元表达式
type IsString<T> = T extends string ? true : false
type Test1 = IsString<string> // true
type Test2 = IsString<number> // false
// 嵌套条件类型
type NonNullable<T> = T extends null | undefined ? never : T
type Test3 = NonNullable<string | null> // string
|
分布式条件类型#
1
2
3
4
5
6
7
8
9
| // 联合类型会分布式应用条件类型
type ToArray<T> = T extends any ? T[] : never
type Test4 = ToArray<string | number> // string[] | number[]
// 阻止分布
type ToArrayNonDistributive<T> = [T] extends [any] ? T[] : never
type Test5 = ToArrayNonDistributive<string | number> // (string | number)[]
|
类型推断#
1
2
3
4
5
6
7
8
9
10
| // Infer关键字
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never
type Fn = (x: number) => string
type Test6 = ReturnType<Fn> // string
// 解包Promise
type UnwrapPromise<T> = T extends Promise<infer U> ? U : T
type Test7 = UnwrapPromise<Promise<string>> // string
|
映射类型#
基础映射类型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 将所有属性变为可选
type Partial<T> = {
[P in keyof T]?: T[P]
}
// 将所有属性变为必需
type Required<T> = {
[P in keyof T]-?: T[P]
}
// 只读
type Readonly<T> = {
readonly [P in keyof T]: T[P]
}
|
高级映射类型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // 只保留特定类型
type OnlyStrings<T> = {
[P in keyof T as T[P] extends string ? P : never]: T[P]
}
interface User {
name: string
age: number
email: string
}
type Test8 = OnlyStrings<User>
// { name: string; email: string }
// 条件映射
type Getters<T> = {
[P in keyof T as `get${Capitalize<string & P>}`]: () => T[P]
}
type Test9 = Getters<{ name: string; age: number }>
// { getName: () => string; getAge: () => number }
|
模板字面量类型#
基础用法#
1
2
3
4
| type Greeting = `hello ${string}`
const test: Greeting = 'hello world' // ✓
const test2: Greeting = 'hi world' // ✗
|
高级应用#
1
2
3
4
5
6
7
8
9
10
| // 事件名称类型
type EventName<T extends string> = `on${Capitalize<T>}`
type Test10 = EventName<'click'> // 'onClick'
// 路径类型
type Path<T extends string> = `/${T}` | `${Path<T>}/${T}`
// 组合类型
type CssValue<T extends number> = `${T}px` | `${T}%` | `${t}em`
|
递归类型#
深度只读#
1
2
3
4
5
6
7
8
9
10
11
12
13
| type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P]
}
interface Config {
database: {
host: string
port: number
}
}
type Test11 = DeepReadonly<Config>
// 所有嵌套属性都变为只读
|
深度必需#
1
2
3
| type DeepRequired<T> = {
[P in keyof T]-?: T[P] extends object ? DeepRequired<T[P]> : T[P]
}
|
品牌类型#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| // 创建唯一类型
type Brand<T, B> = T & { __brand: B }
type USD = Brand<number, 'USD'>
type EUR = Brand<number, 'EUR'>
const usd: USD = 100 as USD
const eur: EUR = 100 as EUR
// 不能直接赋值
// eur = usd // ✗ 类型错误
function addUSD(a: USD, b: USD): USD {
return (a + b) as USD
}
|
函数类型高级应用#
函数重载#
1
2
3
4
5
6
7
8
| function process(input: string): string
function process(input: number): number
function process(input: string | number): string | number {
return input
}
const result1 = process('hello') // string
const result2 = process(123) // number
|
参数类型推断#
1
2
3
4
5
6
7
8
9
10
| // 元组转函数参数
type TupleToFn<T extends any[]> = T extends [...infer Args, infer R]
? (...args: Args) => R
: never
type Test12 = TupleToFn<[string, number, boolean]>
// 反向推断
type FnToTuple<T extends (...args: any[]) => any> =
T extends (...args: infer A) => any ? A : never
|
类型守卫#
typeof守卫#
1
2
3
4
5
6
7
8
9
10
| function isString(value: unknown): value is string {
return typeof value === 'string'
}
function process(value: unknown) {
if (isString(value)) {
// 这里value的类型是string
console.log(value.toUpperCase())
}
}
|
in守卫#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| interface Cat {
meow(): void
}
interface Dog {
bark(): void
}
function makeSound(animal: Cat | Dog) {
if ('meow' in animal) {
animal.meow()
} else {
animal.bark()
}
}
|
instanceof守卫#
1
2
3
4
5
6
7
8
9
10
11
12
13
| class Error1 extends Error {
code = 'ERROR_1'
}
class Error2 extends Error {
code = 'ERROR_2'
}
function handleError(error: Error) {
if (error instanceof Error1) {
console.log(error.code)
}
}
|
高级工具类型#
OmitByType#
1
2
3
4
5
6
7
8
9
10
11
12
| type OmitByType<T, U> = {
[P in keyof T as T[P] extends U ? never : P]: T[P]
}
interface Test {
name: string
age: number
active: boolean
}
type Test13 = OmitByType<Test, boolean>
// { name: string; age: number }
|
DeepPick#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| type DeepPick<T, K extends string> = K extends `${infer Key}.${infer Rest}`
? Key extends keyof T
? { [P in Key]: DeepPick<T[P], Rest> }
: never
: K extends keyof T
? { [P in K]: T[K] }
: never
interface User {
profile: {
name: string
email: string
}
settings: {
theme: string
}
}
type Test14 = DeepPick<User, 'profile.name'>
// { profile: { name: string } }
|
实战案例#
表单类型定义#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| type FieldProps<T> = {
value: T
onChange: (value: T) => void
error?: string
}
type FormFields<T> = {
[K in keyof T]: FieldProps<T[K]>
}
interface LoginData {
email: string
password: string
remember: boolean
}
type LoginForm = FormFields<LoginData>
|
API响应类型#
1
2
3
4
5
6
| type ApiResponse<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E }
type UserResponse = ApiResponse<User>
type ErrorResponse = ApiResponse<never, NetworkError>
|
最佳实践#
- 优先使用类型推导 - 让TypeScript自动推导类型
- 避免使用any - 使用unknown代替
- 合理使用泛型 - 提高代码复用性
- 类型守卫 - 缩小类型范围
- 品牌类型 - 创建语义化类型
TypeScript类型系统非常强大,掌握高级类型特性可以帮助我们构建更安全的代码。