类型体操
00:00
TypeScript类型体操详解:递归类型、斐波那契、深度只读等高级类型编程。
1. 递归类型
1.1 深层 Readonly
type DeepReadonly<T> = T extends Function
? T
: T extends object
? { readonly [K in keyof T]: DeepReadonly<T[K]> }
: T;
type Obj = { a: { b: { c: string } } };
type DeepObj = DeepReadonly<Obj>;
// { readonly a: { readonly b: { readonly c: string } } }
1.2 深层 Partial
type DeepPartial<T> = T extends Function
? T
: T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
1.3 递归展开元组
type Flatten<T extends any[]> = T extends [infer First, ...infer Rest]
? First extends any[]
? [...Flatten<First>, ...Flatten<Rest>]
: [First, ...Flatten<Rest>]
: T;
type A = Flatten<[1, [2, 3], [4, [5]]]>;
// [1, 2, 3, 4, 5]
2. 斐波那契数列
type Fibonacci<
N extends number,
T extends any[] = [1],
U extends any[] = [],
> = T['length'] extends N ? U['length'] : Fibonacci<N, [...T, 1], [...U, ...T]>;
type Fib5 = Fibonacci<5>; // 5
type Fib8 = Fibonacci<8>; // 21
3. 字符串操作
3.1 反转字符串
type Reverse<S extends string> = S extends `${infer First}${infer Rest}`
? `${Reverse<Rest>}${First}`
: S;
type A = Reverse<'hello'>; // 'olleh'
3.2 去除空白
type TrimStart<S extends string> = S extends ` ${infer Rest}` ? TrimStart<Rest> : S;
type TrimEnd<S extends string> = S extends `${infer Rest} ` ? TrimEnd<Rest> : S;
type Trim<S extends string> = TrimEnd<TrimStart<S>>;
4. 对象操作
4.1 深层 Pick
type DeepPick<T, Path extends string> = Path extends `${infer K}.${infer Rest}`
? K extends keyof T
? { [P in K]: DeepPick<T[K], Rest> }
: never
: Path extends keyof T
? { [P in Path]: T[P] }
: never;
type Result = DeepPick<{ a: { b: { c: string } } }, 'a.b.c'>;
// { a: { b: { c: string } } }
4.2 合并类型
type Merge<A, B> = {
[K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never;
};
5. 元组操作
5.1 元组长度
type Length<T extends any[]> = T['length'];
type A = Length<[1, 2, 3]>; // 3
5.2 元组转联合类型
type TupleToUnion<T extends any[]> = T[number];
type A = TupleToUnion<[1, 2, 3]>; // 1 | 2 | 3
5.3 超出计数限制
TypeScript 递归深度限制约 1000 层,超过会报错。对于大数运算需使用查表法:
type NumberMap = {
0: [1];
1: [1, 1];
2: [1, 1, 1];
// ... 预定义到需要的范围
};