模式匹配做提取
实现字符串替换:
type ReplaceStr< Str extends string, From extends string, To extends string > =
Str extends `${infer Prefix}${From}${infer Suffix}`
? `${Prefix}${To}${Suffix}`
: Str;
递归调用循环
- ReverseArr
type ReverseArr<Arr extends unknown[]> =
Arr extends [infer First, ...infer Rest]
? [...ReverseArr<Rest>, First]
: Arr;
- RemoveItem
type RemoveItem< Arr extends unknown[], Item, Result extends unknown[] = [] > =
Arr extends [infer First, ...infer Rest]
? IsEqual<First, Item> extends true
? RemoveItem<Rest, Item, Result>
: RemoveItem<Rest, Item, [...Result, First]>
: Result;
type IsEqual<A, B> = (A extends B ? true : false) & (B extends A ? true : false);
- 递归添加readonly
type DeepReadonly<Obj extends Record<string, any>> = {
readonly [Key in keyof Obj]:
Obj[Key] extends object
? Obj[Key] extends Function
? Obj[Key]
: DeepReadonly<Obj[Key]>
: Obj[Key]
}
- Fibonacci
type FibonacciLoop<
PrevArr extends unknown[],
CurrentArr extends unknown[],
IndexArr extends unknown[] = [],
Num extends number = 1 > =
IndexArr['length'] extends Num
? CurrentArr['length']
: FibonacciLoop<CurrentArr, [...PrevArr, ...CurrentArr], [...IndexArr, unknown], Num>
type Fibonacci<Num extends number> = FibonacciLoop<[1], [], [], Num>;
联合类型
- 条件类型中如果左边的类型是联合类型,会把每个元素单独传入做计算,而右边不会。
type TestUnion<A, B = A> = A extends A ? { a: A, b: B} : never;
type TestUnionResult = TestUnion<'a' | 'b' | 'c'>;
- isUnion
type IsUnion<A, B = A> =
A extends A
? [B] extends [A]
? false
: true
: never
- BEM
type BEM<
Block extends string,
Element extends string[],
Modifiers extends string[] > =`${Block}__${Element[number]}--${Modifiers[number]}`;
- AllCombinations
type Combination<A extends string, B extends string> =
| A
| B
| `${A}${B}`
| `${B}${A}`;
type AllCombinations<A extends string, B extends string = A> =
A extends A
? Combination<A, AllCombinations<Exclude<B, A>>>
: never;
类型参数 A、B 是待组合的两个联合类型,B 默认是 A 也就是同一个。
A extends A 的意义就是让联合类型每个类型单独传入做处理。
A 的处理=> A 和 B 中去掉 A 以后的所有类型组合=> Combination<A, B 去掉 A 以后的所有组合>。
而 B 去掉 A 以后的所有组合就是 AllCombinations<Exclude<B, A>>
所以全组合就是 Combination<A, AllCombinations<Exclude<B, A>>>。
- 联合转交叉 逆变
type UnionToIntersection<U> =
(U extends U ? (x: U) => unknown : never) extends (x: infer R) => unknown
? R
: never
- GetOptional
type GetOptional<Obj extends Record<string, any>> ={
[
Key in keyof Obj
as {} extends Pick<Obj, Key> ? Key : never
]
: Obj[Key];
}
type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
利用Pick构造子集,当某个key是可选时,会有落入undefined的情况,会构造出{}
这时通过 Key in keyof Obj as {} extends Pick<Obj, Key>
即可判断 该ket是optional
- GetRequire
type isRequired<Key extends keyof Obj, Obj> =
{} extends Pick<Obj, Key> ? never : Key;
type GetRequired<Obj extends Record<string, any>> = {
[Key in keyof Obj as isRequired<Key, Obj>]: Obj[Key]
}
- 去掉type中的可索引签名
type Dong = {
[key: string]: any;
sleep(): void;
}
type RemoveIndexSignature<Obj extends Record<string, any>> = {
[
Key in keyof Obj
as Key extends `${infer Str}`? Str : never
]: Obj[Key]
}
type result =RemoveIndexSignature<Dong>
//type result = { sleep(): void; }
如果索引是字符串字面量类型,那么就保留,否则返回 never,代表过滤掉。
模式匹配做提取
- GetReturnType
type GetReturnType<Func extends Function> =
Func extends (...args: unknown[]) => infer ReturnType
? ReturnType
: never;
重新构造做变换
- UppercaseKey
type UppercaseKey<Obj extends Record<string, any>> = {
[
Key in keyof Obj
as Uppercase<Key & string>
]: Obj[Key]
}
递归复用做循环
- StringToUnion
type StringToUnion<Str extends string> =
Str extends `${infer First}${infer Rest}`
? First | StringToUnion<Rest>
: never;
数组长度做计数
- 实现减法
type BuildArray<
Length extends number,
Ele = unknown,
Arr extends unknown[] = []
>
= Arr['length'] extends Length
? Arr
: BuildArray<Length, Ele, [...Arr, Ele]>;
type Subtract<Num1 extends number, Num2 extends number> =
BuildArray<Num1> extends [...arr1: BuildArray<Num2>, ...arr2: infer Rest]
? Rest['length']
: never;
实践
-
解析并合并多个type => ParseQueryString
-
对curry函数添加类型 => CurriedFunc
type CurriedFunc<Params, Return> =
Params extends []
? () => Return
: Params extends [infer Arg]
? (arg: Arg) => Return
: Params extends [infer Arg, ...infer Rest]
? (arg: Arg) => CurriedFunc<Rest, Return>
: never;
declare function currying<Func>(fn: Func):
Func extends (...args: infer Params) => infer Result
? CurriedFunc<Params, Result>
: never;