TypeScript 高级类型体操:类型系统完全指南
·
前言
💡 痛点:看不懂复杂的泛型约束?写不出高级类型工具?TypeScript 类型系统深似海?
🎯 解决方案:从条件类型到映射类型,从模板字面量到递归类型,手把手教你玩转 TypeScript 类型系统。
为什么要深入 TypeScript 类型系统?
本文目标: 让你从"会用 TypeScript"到"精通类型系统、写出优雅类型工具"。
一、条件类型基础
1.1 条件类型语法
// ===== 条件类型基础 =====
// 语法:T extends U ? X : Y
// 如果 T 是 U 的子类型,返回 X,否则返回 Y
// 基础示例
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false
type C = IsString<"hello">; // true(字面量是 string 子类型)
// 泛型条件类型
type ExtractArray<T> = T extends any[] ? T : never;
type D = ExtractArray<string[]>; // string[]
type E = ExtractArray<number>; // never
type F = ExtractArray<string>; // never
// never 是底类型,表示"无任何类型"
type G = ExtractArray<any[]>; // any[]
1.2 分布条件类型
// ===== 分布条件类型 =====
// 条件类型在联合类型上是"分布式"的
type ToArray<T> = T extends any ? T[] : never;
type H = ToArray<string | number>;
// 分布计算:(string extends any ? string[] : never) | (number extends any ? number[] : never)
// 结果:string[] | number[]
type I = ToArray<"a" | "b" | "c">;
// 结果:("a")[] | ("b")[] | ("c")[]
// 即:"a"[] | "b"[] | "c"[]
// 如果不想分布,使用元组包装
type ToArrayNonDist<T> = [T] extends [any] ? T[] : never;
type J = ToArrayNonDist<string | number>;
// 结果:(string | number)[](不分布)
// ===== 常用工具类型的条件类型实现 =====
// 实现 Awaited<T>
type Awaited<T> =
T extends null | undefined ? T :
T extends object & { then: infer F } ?
F extends (value: infer V, ...args: any) ? Awaited<V> :
never :
T;
// 测试
type K = Awaited<Promise<string>>; // string
type L = Awaited<Promise<Promise<number>>>; // number
type M = Awaited<"hello">; // "hello"
1.3 条件类型与 infer
// ===== infer 关键字 =====
// infer 用于在条件类型中提取类型
// 提取函数返回值类型
type ReturnType<T> = T extends (...args: any) => infer R ? R : never;
type N = ReturnType<() => string>; // string
type O = ReturnType<(x: number) => boolean>; // boolean
type P = ReturnType<() => Promise<number>>; // Promise<number>
// 提取函数参数类型
type Parameters<T> = T extends (...args: infer P) => any ? P : never;
type Q = Parameters<(name: string, age: number) => void>; // [string, number]
type R = Parameters<(x: number) => boolean>; // [number]
// 提取构造函数参数
type ConstructorParameters<T> =
T extends new (...args: infer P) => any ? P : never;
class Person {
constructor(public name: string, public age: number) {}
}
type S = ConstructorParameters<typeof Person>; // [string, number]
// 提取数组元素类型
type ElementType<T> = T extends (infer E)[] ? E : never;
type T_array = ElementType<string[]>; // string
type U_array = ElementType<number[]>; // number
type V_array = ElementType<(string | number)[]>; // string | number
// 提取 Promise resolve 类型
type UnwrapPromise<T> = T extends Promise<infer V> ? V : T;
type W = UnwrapPromise<Promise<string>>; // string
type X = UnwrapPromise<number>; // number
二、映射类型
2.1 基础映射类型
// ===== 基础映射类型 =====
// 语法:{ [K in keyof T]: ... }
type Person = {
name: string;
age: number;
email: string;
};
// 将所有属性转为可选
type Partial<T> = { [K in keyof T]?: T[K] };
type PartialPerson = Partial<Person>;
// { name?: string; age?: number; email?: string; }
// 将所有属性转为必填
type Required<T> = { [K in keyof T]-?: T[K] };
type RequiredPerson = Required<PartialPerson>; // 回到 Person
// 将所有属性转为只读
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type ReadonlyPerson = Readonly<Person>;
// { readonly name: string; readonly age: number; readonly email: string; }
// 提取特定属性
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type PersonName = Pick<Person, "name">;
// { name: string; }
// 排除特定属性
type Omit<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P] };
type PersonWithoutAge = Omit<Person, "age">;
// { name: string; email: string; }
2.2 映射类型修饰符
// ===== 映射类型修饰符 =====
// -?: 移除可选修饰符
// +?: 添加可选修饰符
// readonly: 添加只读修饰符
// -readonly: 移除只读修饰符
type CreateOptional<T> = { [K in keyof T]?: T[K] };
type CreateReadonly<T> = { readonly [K in keyof T]: T[K] };
// 条件映射:只映射满足条件的属性
type PickByValue<T, V> = {
[K in keyof T as T[K] extends V ? K : never]: T[K];
};
type Mixed = { name: string; age: number; active: boolean };
type StringProps = PickByValue<Mixed, string>; // { name: string }
// ===== 使用 as 重映射键 =====
// TypeScript 4.1+ 支持
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number; getEmail: () => string }
// 移除某属性
type RemoveProperty<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
// 条件添加属性
type MaybeNull<T> = T extends object ? T & { null: null } : never;
2.3 映射类型进阶
// ===== 映射类型进阶 =====
// 根据键值类型映射
type MapValues<T, V> = {
[K in keyof T]: V;
};
type StringRecord = MapValues<{ a: number; b: string }, boolean>;
// { a: boolean; b: boolean }
// 递归映射
type DeepReadonly<T> =
T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
type Nested = { user: { profile: { name: string } } };
type DeepReadonlyNested = DeepReadonly<Nested>;
// { readonly user: { readonly profile: { readonly name: string } } }
// 深度可选
type DeepPartial<T> =
T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
// ===== 使用模板字面量映射键 =====
type EventHandlers<T> = {
[K in keyof T as `on${Capitalize<string & K>}Change`]: (value: T[K]) => void;
};
type State = { count: number; name: string };
type Handlers = EventHandlers<State>;
// { onCountChange: (value: number) => void; onNameChange: (value: string) => void; }
// 键值对互换
type Flip<T> = {
[K in keyof T as T[K] extends string | number ? T[K] : never]: K
};
type Status = { pending: "pending"; active: "active"; done: "done" };
type Flipped = Flip<Status>;
// { pending: "pending"; active: "active"; done: "done" }
// 实际效果:值变成键,键变成值
三、模板字面量类型
3.1 基础模板字面量
// ===== 基础模板字面量类型 =====
type World = "world";
type Greeting = `hello, ${World}`; // "hello, world"
// 连接字符串
type Email = `${string}@${string}.${string}`;
const validEmail: Email = "user@example.com";
// const invalidEmail: Email = "not-an-email"; // ❌ 错误
// 使用泛型
type SuccessMessage<T> = `Success: ${T}`;
type ErrorMessage<T> = `Error: ${T}`;
type A = SuccessMessage<"User created">; // "Success: User created"
type B = ErrorMessage<"Not found">; // "Error: Not found"
// 联合类型组合
type Direction = "top" | "right" | "bottom" | "left";
type EventName = `on${Capitalize<Direction>}`;
type Events = { [K in EventName]: () => void };
// { onTop: () => void; onRight: () => void; onBottom: () => void; onLeft: () => void; }
3.2 模板字面量与映射类型
// ===== 模板字面量与映射类型 =====
// 自动生成 getter/setter
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
type Setters<T> = {
[K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void
};
type Model = { name: string; age: number };
type ModelGetters = Getters<Model>;
// { getName: () => string; getAge: () => number; }
type ModelSetters = Setters<Model>;
// { setName: (value: string) => void; setAge: (value: number) => void; }
// 组合 getter 和 setter
type Accessors<T> = Getters<T> & Setters<T>;
type ModelAccessors = Accessors<Model>;
// { getName: () => string; setName: (value: string) => void; ... }
// ===== 字符串操作类型 =====
// Uppercase, Lowercase, Capitalize, Uncapitalize
type A1 = Uppercase<"hello">; // "HELLO"
type A2 = Lowercase<"WORLD">; // "world"
type A3 = Capitalize<"hello">; // "Hello"
type A4 = Uncapitalize<"Hello">; // "hello"
// 递归字符串处理
type Split<S extends string, D extends string = ""> =
S extends `${infer Head}${D}${infer Tail}`
? [Head, ...Split<Tail, D>]
: S extends "" ? [] : [S];
type B1 = Split<"a-b-c", "-">; // ["a", "b", "c"]
type B2 = Split<"hello world", " ">; // ["hello", "world"]
type Join<T extends string[], D extends string = ""> =
T extends [] ? "" :
T extends [infer F extends string, ...infer R extends string[]]
? F extends "" ? Join<R, D> : `${F}${D}${Join<R, D>}` : "";
type C1 = Join<["a", "b", "c"], "-">; // "a-b-c"
type C2 = Join<["hello", "world"], " "> // "hello world"
3.3 实际应用场景
// ===== 模板字面量实际应用 =====
// 1. CSS-in-JS 类型
type CSSProperties = {
[K in `css\${string}`]?: string | number;
};
const styles: CSSProperties = {
cssColor: "red",
cssFontSize: "14px",
cssMarginTop: 10,
};
// 2. 事件系统类型
type EventMap = {
click: { x: number; y: number };
keydown: { key: string };
resize: { width: number; height: number };
};
type EventHandler<K extends keyof EventMap> = (event: EventMap[K]) => void;
function addEventListener<K extends keyof EventMap>(
event: K,
handler: EventHandler<K>
): void {
// 实现...
}
// 3. API 路由类型
type Routes = {
"/users": { id: string; name: string };
"/posts": { id: string; title: string };
};
type Handler<M extends keyof Routes> = (data: Routes[M]) => void;
function registerRoute<M extends keyof Routes>(
path: M,
handler: Handler<M>
): void {
// 实现...
}
// 4. GraphQL 类型
type FieldSelection<T> = {
[K in keyof T]?: boolean | FieldSelection<T[K]>
};
type UserSelection = FieldSelection<{
id: string;
name: string;
email: string;
profile: { avatar: string }
}>;
// { id?: boolean; name?: boolean; email?: boolean; profile?: FieldSelection<{ avatar: string }> }
四、递归类型
4.1 递归基础
// ===== 递归类型基础 =====
// 树形结构
interface TreeNode<T> {
value: T;
children: TreeNode<T>[];
}
// JSON 类型
type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
// 深度递归类型
type DeepRequired<T> = T extends object
? { [K in keyof T]-?: DeepRequired<T[K]> }
: T;
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
type DeepReadonly<T> = T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
// 测试
type Config = {
server: {
host: string;
port: number;
};
database: {
connection: {
url: string;
pool: number;
};
};
};
type DeepRequiredConfig = DeepRequired<Config>;
// 所有嵌套属性都变成必填
type DeepPartialConfig = DeepPartial<Config>;
// 所有嵌套属性都变成可选
4.2 列表操作
// ===== 列表操作类型 =====
// 不可变列表操作
// Head - 获取列表第一个元素
type Head<T extends any[]> = T extends [infer H, ...any[]] ? H : never;
type H1 = Head<[1, 2, 3]>; // 1
type H2 = Head<string[]>; // string
// Tail - 获取列表除第一个外的元素
type Tail<T extends any[]> = T extends [any, ...infer TAIL] ? TAIL : never;
type T1 = Tail<[1, 2, 3]>; // [2, 3]
type T2 = Tail<string[]>; // string[]
// Last - 获取列表最后一个元素
type Last<T extends any[]> = T extends [...any[], infer L] ? L : never;
type L1 = Last<[1, 2, 3]>; // 3
type L2 = Last<string[]>; // string
// Prepend - 在列表开头添加元素
type Prepend<T extends any[], V> = [V, ...T];
type P1 = Prepend<[2, 3], 1>; // [1, 2, 3]
type P2 = Prepend<string[], number>; // [number, ...string[]]
// Append - 在列表末尾添加元素
type Append<T extends any[], V> = [...T, V];
type A1 = Append<[1, 2], 3>; // [1, 2, 3]
// Concat - 连接两个列表
type Concat<T extends any[], U extends any[]> = [...T, ...U];
type C1 = Concat<[1, 2], [3, 4]>; // [1, 2, 3, 4]
// Reverse - 反转列表
type Reverse<T extends any[], R extends any[] = []> =
T extends [infer H, ...infer TAIL]
? Reverse<TAIL, [H, ...R]>
: R;
type R1 = Reverse<[1, 2, 3]>; // [3, 2, 1]
// Flatten - 展平嵌套列表
type Flatten<T extends any[]> =
T extends [infer H, ...infer TAIL]
? H extends any[]
? [...Flatten<H>, ...Flatten<TAIL>]
: [H, ...Flatten<TAIL>]
: [];
type F1 = Flatten<[1, [2, 3], [4, [5, 6]]]>; // [1, 2, 3, 4, 5, 6]
4.3 路径与访问
// ===== 路径访问类型 =====
// 深层属性访问
type DeepGet<T, Path extends string> =
Path extends `${infer K}.${infer Rest}`
? K extends keyof T
? DeepGet<T[K], Rest>
: never
: Path extends keyof T
? T[Path]
: never;
interface User {
profile: {
address: {
city: string;
zip: string;
};
};
settings: {
theme: string;
};
}
type City = DeepGet<User, "profile.address.city">; // string
type Theme = DeepGet<User, "settings.theme">; // string
// 可选路径访问
type DeepGetOptional<T, Path extends string> =
Path extends `${infer K}.${infer Rest}`
? K extends keyof T
? DeepGetOptional<T[K], Rest>
: undefined
: Path extends keyof T
? T[Path]
: undefined;
// ===== 路径设置类型 =====
// 设置深层属性
type DeepSet<T, Path extends string, Value> =
Path extends `${infer K}.${infer Rest}`
? K extends keyof T
? { [P in K]: DeepSet<T[K], Rest, Value> } & Omit<T, K>
: never
: Path extends keyof T
? { [P in keyof T]: P extends Path ? Value : T[P] }
: never;
type UpdatedUser = DeepSet<User, "profile.address.city", "Beijing">;
// { profile: { address: { city: "Beijing"; zip: string }; }; settings: { theme: string; } }
// 深度合并
type DeepMerge<T, U> =
T extends object
? U extends object
? { [K in keyof (T & U)]:
K extends keyof T
? K extends keyof U
? DeepMerge<T[K], U[K]>
: T[K]
: K extends keyof U
? U[K]
: never
}
: U
: U;
type X = DeepMerge<{ a: { x: number } }, { a: { y: string } }>;
// { a: { x: number; y: string } }
五、分配与高阶类型
5.1 类型分配
// ===== 类型分配 =====
// Union 分配
type ToString<T> = T extends any ? `${T}` : never;
type S1 = ToString<string | number | boolean>;
// 分配结果:"string" | "number" | "boolean"
type S2 = ToString<"a" | "b">;
// "a" | "b"
// ===== Filter Union =====
// 从 Union 中提取特定类型
type ExtractType<T, U> = T extends U ? T : never;
type Mixed = string | number | boolean;
type Strings = ExtractType<Mixed, string>; // string
type Numbers = ExtractType<Mixed, number>; // number
// ===== Exclude 简化实现 =====
type Exclude<T, U> = T extends U ? never : T;
type StringsOnly = Exclude<"a" | 1 | "b" | 2, number>; // "a" | "b"
// ===== 递归 Union 处理 =====
// Union 转 Intersection
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
type I1 = UnionToIntersection<string | number>;
// string & number = never(简单类型无法交叉)
type I2 = UnionToIntersection<{ a: string } | { b: number }>;
// { a: string } & { b: number }
5.2 高阶类型工厂
// ===== 高阶类型工厂 =====
// 类型柯里化
type Curried<T> =
T extends (...args: infer Args) => infer R
? Args extends [infer A, ...infer Rest]
? (arg: A) => Curried<(...args: Rest) => R>
: () => R
: never;
type Add = (a: number, b: number) => number;
type CurriedAdd = Curried<Add>;
// (a: number) => (b: number) => number
type ThreeArgs = (a: number, b: string, c: boolean) => void;
type CurriedThree = Curried<ThreeArgs>;
// (a: number) => (b: string) => (c: boolean) => void
// ===== 类型组合器 =====
// Or 类型
type Or<A extends boolean, B extends boolean> = A extends true ? true : B;
// And 类型
type And<A extends boolean, B extends boolean> = A extends true ? B : false;
// Not 类型
type Not<T extends boolean> = T extends true ? false : true;
// Xor 类型(异或)
type Xor<A extends boolean, B extends boolean> =
[A, B] extends [true, true] ? false :
[A, B] extends [false, false] ? false :
true;
// 测试
type T1 = Or<true, false>; // true
type T2 = And<true, true>; // true
type T3 = Not<true>; // false
type T4 = Xor<true, false>; // true
六、实用类型工具集
6.1 常见工具类型实现
// ===== 常用工具类型实现 =====
// Partial<T> - 将所有属性变为可选
type MyPartial<T> = { [P in keyof T]?: T[P] };
// Required<T> - 将所有属性变为必填
type MyRequired<T> = { [P in keyof T]-?: T[P] };
// Readonly<T> - 将所有属性变为只读
type MyReadonly<T> = { readonly [P in keyof T]: T[P] };
// Pick<T, K> - 提取属性
type MyPick<T, K extends keyof T> = { [P in K]: T[P] };
// Omit<T, K> - 排除属性
type MyOmit<T, K extends keyof T> = { [P in Exclude<keyof T, K>]: T[P] };
// Record<K, V> - 创建键值类型
type MyRecord<K extends keyof any, V> = { [P in K]: V };
// Exclude<T, U> - 排除类型
type MyExclude<T, U> = T extends U ? never : T;
// Extract<T, U> - 提取类型
type MyExtract<T, U> = T extends U ? T : never;
// NonNullable<T> - 排除 null 和 undefined
type MyNonNullable<T> = T extends null | undefined ? never : T;
// ReturnType<T> - 获取函数返回值类型
type MyReturnType<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : never;
// Parameters<T> - 获取函数参数类型
type MyParameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never;
// ConstructorParameters<T> - 获取构造函数参数
type MyConstructorParameters<T extends new (...args: any) => any> =
T extends new (...args: infer P) => any ? P : never;
// InstanceType<T> - 获取实例类型
type MyInstanceType<T extends new (...args: any) => any> =
T extends new (...args: any) => infer I ? I : never;
6.2 高级工具类型
// ===== 高级工具类型 =====
// Mutable<T> - 移除只读
type Mutable<T> = { -readonly [P in keyof T]: T[P] };
// DeepMutable<T> - 递归移除只读
type DeepMutable<T> = T extends object
? { -readonly [P in keyof T]: DeepMutable<T[P]> }
: T;
// RequiredKeys<T> - 获取必填键
type RequiredKeys<T> = {
[K in keyof T]-?: undefined extends T[K] ? never : K
}[keyof T];
// OptionalKeys<T> - 获取可选键
type OptionalKeys<T> = {
[K in keyof T]-?: undefined extends T[K] ? K : never
}[keyof T];
// UnionToTuple<T> - Union 转 Tuple
type UnionToTuple<T> =
([T] extends [never] ? [] :
((T extends any ? (t: T) => T : never) extends (t: infer U) ? [U] : never));
type T1 = UnionToTuple<"a" | "b" | "c">; // ["a", "b", "c"]
// IsNever<T> - 判断是否为 never
type IsNever<T> = [T] extends [never] ? true : false;
type N1 = IsNever<never>; // true
type N2 = IsNever<string>; // false
// IsAny<T> - 判断是否为 any
type IsAny<T> = 0 extends (1 & T) ? true : false;
type A1 = IsAny<any>; // true
type A2 = IsAny<string>; // false
// IsEqual<T, U> - 判断类型是否相等
type IsEqual<A, B> =
(<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2)
? true : false;
type E1 = IsEqual<string, string>; // true
type E2 = IsEqual<string, number>; // false
6.3 函数类型工具
// ===== 函数类型工具 =====
// PartialApply - 部分应用
type PartialApply<F, A extends keyof Parameters<F>> =
(...args: { [K in A]: Parameters<F>[K] }) => ReturnType<F>;
// Overload - 函数重载类型
type Overload<F extends any[], R> = {
(...args: F): R;
};
// Callable - 检测可调用
type Callable<T> = T extends (...args: any[]) => any ? true : false;
// 安全的参数替换
type ReplaceFirst<T extends any[], A, B> =
T extends [infer First, ...infer Rest]
? First extends A ? [B, ...Rest] : [First, ...ReplaceFirst<Rest, A, B>]
: T;
// 测试
type R1 = ReplaceFirst<[string, number, boolean], string, Date>;
// [Date, number, boolean]
// 延迟类型计算
type Deferred<T> = T | (() => T);
type ResolveDeferred<T> = T extends () => infer R ? R : T;
七、实战案例
7.1 表单验证类型
// ===== 表单验证类型系统 =====
// 验证规则类型
type ValidationRule<T> =
| { type: "required" }
| { type: "minLength"; value: number }
| { type: "maxLength"; value: number }
| { type: "pattern"; value: RegExp }
| { type: "custom"; validator: (value: T) => boolean };
// 表单字段类型
interface FormField<T> {
value: T;
rules: ValidationRule<T>[];
error?: string;
touched: boolean;
}
// 验证器函数
type Validator<T> = {
[K in keyof T]: FormField<T[K]>;
};
// 验证表单
function validateForm<T>(form: Validator<T>): boolean {
// 实现验证逻辑...
return true;
}
// 使用示例
interface UserForm {
name: FormField<string>;
email: FormField<string>;
age: FormField<number>;
}
const userForm: Validator<UserForm> = {
name: {
value: "John",
rules: [{ type: "required" }, { type: "minLength", value: 2 }],
touched: true,
},
email: {
value: "john@example.com",
rules: [
{ type: "required" },
{ type: "pattern", value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/ }
],
touched: false,
},
age: {
value: 25,
rules: [{ type: "required" }],
touched: true,
},
};
7.2 状态管理类型
// ===== 状态管理类型系统 =====
// Action 类型
interface Action<T = any, P = any> {
type: T;
payload?: P;
}
// Reducer 类型
type Reducer<S, A extends Action> = (state: S, action: A) => S;
// Middleware 类型
type Middleware<S, A extends Action> = (
store: { getState(): S; dispatch(a: A): void }
) => (next: (a: A) => void) => (action: A) => void;
// 创建 Store 的类型
interface Store<S, A extends Action = Action> {
getState(): S;
dispatch(action: A): void;
subscribe(listener: () => void): () => void;
}
// Thunk 类型
type Thunk<S, A extends Action> = (dispatch: (a: A) => void, getState: () => S) => void;
type AsyncAction<S, A extends Action> = Thunk<S, A> | A;
// 状态选择器
type Selector<S, R> = (state: S) => R;
// 创建带类型的选择器工厂
function createSelector<S, R>(selector: Selector<S, R>) {
return selector;
}
7.3 路由系统类型
// ===== 路由系统类型 =====
// 路由定义
interface Route<
Path extends string,
Params extends string[] = [],
Query extends string[] = [],
Body = unknown
> {
path: Path;
params: Params;
query: Query;
body: Body;
}
// 解析路由参数
type ParseParams<Path extends string> =
Path extends `${string}:${infer Param}/${infer Rest}`
? [Param, ...ParseParams<`/${Rest}`>]
: Path extends `${string}:${infer Param}`
? [Param]
: [];
type Params1 = ParseParams<"/users/:id/posts/:postId">;
// ["id", "postId"]
type Params2 = ParseParams<"/users">;
// []
// 路径参数
type PathParams<Path extends string> = {
[K in ParseParams<Path> as K]: string;
};
// 生成路径
type BuildPath<Path extends string, Params extends keyof any = never> =
Path extends `${string}:${infer Param}/${infer Rest}`
? Param extends Params
? `${string}/{${Param}}:${BuildPath<`/${Rest}`, Params>}`
: never
: Path extends `${string}:${infer Param}`
? Param extends Params
? `${string}/{${Param}}`
: never
: Path;
type BuiltPath = BuildPath<"/users/:id", "id">;
// "/users/{id}"
// 链接组件
interface LinkProps<Path extends string> {
to: Path;
params?: PathParams<Path>;
query?: Record<string, string>;
children: React.ReactNode;
}
八、性能与调试
8.1 类型性能
// ===== 类型计算性能 =====
// 避免深层嵌套
// ❌ 差:深度嵌套导致编译器变慢
type DeepNested<T> = { [K in keyof T]: DeepNested<T[K]> };
// ✅ 好:限制递归深度
type DeepNestedLimited<T, Depth extends number[]> =
Depth["length"] extends 0 ? T :
T extends object ? { [K in keyof T]: DeepNestedLimited<T[K], [-1, ...Depth]> } : T;
// 使用条件类型优化
type FastExtract<T, U> = T extends U ? T : never; // 比 T extends any ? T : never 快
// 避免在映射类型中使用复杂计算
// ❌ 差
type SlowMap<T> = { [K in keyof T]: SomeComplexComputation<T[K]> };
// ✅ 好:先计算再映射
type Precomputed = SomeComplexComputation<T[keyof T]>;
type FastMap<T> = { [K in keyof T]: Precomputed };
8.2 类型调试技巧
// ===== 类型调试技巧 =====
// 使用 TODO 注释标记待处理类型
type TODO<T> = T;
// 使用 never 检测不可能的情况
type AssertNever<T> = T extends never ? true : false;
// 检查类型是否正确
type Check<T, Expected> = [T] extends [Expected] ? [Expected] extends [T] ? true : false : false;
// 打印类型(用于调试)
type Debug<T> = { [K in keyof T]: T[K] };
type Reveal<T> = T extends infer U ? U : never;
// 使用 const 断言辅助类型推断
const config = {
api: {
baseUrl: "https://api.example.com",
timeout: 5000,
} as const,
} as const;
type ConfigType = typeof config;
// { readonly api: { readonly baseUrl: "https://api.example.com"; readonly timeout: 5000 } }
// 使用 satisfies 验证
const colors = {
red: "#ff0000",
green: "#00ff00",
blue: "#0000ff",
} satisfies Record<string, string>;
8.3 类型测试
// ===== 类型测试 =====
import { expectType } from "ts-expect";
// 类型级别测试
type Test<
Actual extends string,
Expected extends string
> = Actual extends Expected
? Expected extends Actual
? true
: false
: false;
// 示例测试
type Test1 = Test<ParseParams<"/users/:id">, ["id"]>; // true
type Test2 = Test<ParseParams<"/users">, []>; // true
type Test3 = Test<ParseParams<"/posts/:postId">, ["id"]>; // false
// 编译时断言
type Assert<T extends true> = T;
// 使用 Assert 确保条件成立
type AssertIsString<T> = T extends string ? Assert<true> : Assert<false>;
// 快速检查工具
type IsString<T> = T extends string ? "yes" : "no";
type IsArray<T> = T extends any[] ? "yes" : "no";
type IsObject<T> = T extends object ? "yes" : "no";
九、常见错误与解决
9.1 泛型约束错误
// ===== 常见泛型错误 =====
// 错误 1:约束不足
function first<T>(arr: T): T[0] { // ❌ T 可能没有索引
return arr[0];
}
// 解决:添加约束
function first<T extends any[]>(arr: T): T[0] {
return arr[0];
}
// 错误 2:约束过严
function identity<T extends string>(value: T): T { // ❌ 无法传入 number
return value;
}
// 解决:使用更宽泛的约束
function identity<T>(value: T): T {
return value;
}
// 错误 3:没有处理 never
type Extract<T, U> = T extends U ? T : never;
type Result = string | never; // 永远是 string
// never 被自动移除
// 正确理解分布
type Test = "a" | "b" | "c" extends string ? true : false; // true
// 联合类型作为整体比较
9.2 递归类型问题
// ===== 递归类型问题 =====
// 问题 1:类型太深导致循环
// ❌ 可能的无限递归
type DeepExpand<T> = T extends infer U ? { [K in keyof U]: DeepExpand<U[K]> } : T;
// 可能超出 TypeScript 限制
// 解决:添加深度限制
type DeepExpandLimited<T, Depth extends number = 5> =
Depth extends 0
? T
: T extends object
? { [K in keyof T]: DeepExpandLimited<T[K], [-1, ...Depth]> }
: T;
// 问题 2:协变与逆变
interface Container<T> {
value: T;
setValue: (value: T) => void; // 逆变
getValue: () => T; // 协变
}
// 问题 3:any 类型导致的意外结果
type Test1 = any extends string ? true : false; // true(any 太宽泛)
type Test2 = string extends any ? true : false; // true
// 解决:使用 unknown 而非 any
type Test3 = unknown extends string ? true : false; // false
9.3 映射类型问题
// ===== 映射类型问题 =====
// 问题 1:索引签名冲突
type A = { [key: string]: string };
type B = { [key: string]: number };
type AB = A & B; // { [key: string]: string & number } = never
// 问题 2:可选属性处理
type Partial<T> = { [K in keyof T]?: T[K] };
// 可选属性可能包含 undefined
// 问题 3:只读属性处理
type Readonly<T> = { readonly [K in keyof T]: T[K] };
// 嵌套对象内部的属性可能仍然可变
// 解决:递归版本
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
// 问题 4:键重映射中使用 never
type RemoveNull<T> = { [K in keyof T as T[K] extends null ? never : K]: T[K] };
// 正确使用 never 作为键
十、总结
10.1 知识体系总结
10.2 学习路线图
10.3 推荐资源
| 类型 | 资源 | 说明 |
|---|---|---|
| 官方文档 | TypeScript Handbook | https://www.typescriptlang.org/docs/ |
| 书籍 | 《Programming TypeScript》 | 全面深入 |
| 网站 | type-challenges | 类型体操练习 |
| 网站 | Total TypeScript | 免费教程 |
| 工具 | tsd | 类型测试 |
附录:速查表
A. 常用工具类型
// 基础工具
Partial<T>
Required<T>
Readonly<T>
Pick<T, K>
Omit<T, K>
Record<K, V>
Exclude<T, U>
Extract<T, U>
NonNullable<T>
ReturnType<T>
Parameters<T>
// 高级工具
Mutable<T>
DeepPartial<T>
DeepReadonly<T>
RequiredKeys<T>
OptionalKeys<T>
IsNever<T>
IsAny<T>
IsEqual<A, B>
// 列表工具
Head<T>
Tail<T>
Last<T>
Prepend<T, V>
Append<T, V>
Reverse<T>
B. 类型操作符
// 条件类型
T extends U ? X : Y
// infer
T extends infer U ? U : never
// 键重映射
[K in keyof T as ...]: T[K]
// 模板字面量
`${string}${T}`
本文基于 TypeScript 4.5+ 编写。如有问题欢迎评论区讨论!
更多推荐
所有评论(0)