TypeScript 的类型体操笔记,温故知新。
LastIndexOf 、数组去重 Unique 、MapTypes
Construct Tuple 、Number Range 、Combination
中等挑战
一、LastIndexOf
实现类型版本的 Array.lastIndexOf
, LastIndexOf<T, U>
接受数组 T
, any
类型 U
, 如果 U
存在于 T
中, 返回 U
在数组 T
中最后一个位置的索引, 不存在则返回 -1
type IsEqual<T, U> = U extends T ? (T extends U ? true : false) : false;
type LastIndexOf<T extends any[], U> = T extends [...infer L, infer R] ? (IsEqual<R, U> extends true ? L["length"] : LastIndexOf<L, U>) : -1;
二、数组去重Unique
实现类型版本的 Lodash.uniq
方法, Unique
接收数组类型 T
, 返回去重后的数组类型.
type IsInclude<T, U> = U extends [infer F, ...infer Rest] ? (Equal<F, T> extends true ? true : IsInclude<T, Rest>) : false;
type Unique<T, U extends any[] = []> = T extends [infer R, ...infer F] ? (IsInclude<R, U> extends true ? Unique<F, [...U]> : Unique<F, [...U, R]>) : U;
三、MapTypes
type StringToNumber = { mapFrom: string; mapTo: number };
type StringToDate = { mapFrom: string; mapTo: Date };
MapTypes<{ iWillBeNumberOrDate: string }, StringToDate | StringToNumber>; // gives { iWillBeNumberOrDate: number | Date; }
type MapTypes<T, R extends { mapFrom: any; mapTo: any }> = {
[K in keyof T]: T[K] extends R["mapFrom"] ? (R extends { mapFrom: T[K] } ? R["mapTo"] : never) : T[K];
};
四、Construct Tuple
构造一个给定长度的元组。
type result = ConstructTuple<2> // 期望得到 [unknown, unkonwn]
type ConstructTuple<L extends number, U extends unknown[] = []> = L extends U["length"] ? U : ConstructTuple<L, [...U, unknown]>;
五、Number Range
Sometimes we want to limit the range of numbers… For examples.
type result = NumberRange<2 , 9> // | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
type NumberRange<L extends number, H extends number, Idx extends 1[] = L extends 0 ? [] : [1, 1], Res = never> = Idx["length"] extends H
? H | Res
: NumberRange<L, H, [...Idx, 1], Idx["length"] | Res>;
六、Combination
Given an array of strings, do Permutation & Combination. It’s also useful for the prop types like video controlsList
For example:
// expected to be `"foo" | "bar" | "baz" | "foo bar" | "foo bar baz" | "foo baz" | "foo baz bar" | "bar foo" | "bar foo baz" | "bar baz" | "bar baz foo" | "baz foo" | "baz foo bar" | "baz bar" | "baz bar foo"`
type Keys = Combination<["foo", "bar", "baz"]>;
Answer:
type Combination<T extends string[], All = T[number], Item = All> = Item extends string ? Item | `${Item} ${Combination<[], Exclude<All, Item>>}` : never;