小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
序言:
这是搞定 TS 第八篇,如果没有基础的小伙伴想要从零搞定 TS ,请从第一篇开始juejin.cn/post/701033…
第一题
实现一个 Includes 工具类型,用于判断指定的类型 E 是否包含在 T 数组类型中。具体的使用示例如下所示:
type Includes<T extends Array<any>, E> = // 你的实现代码
type I0 = Includes<[], 1> // false
type I1 = Includes<[2, 2, 3, 1], 2> // true
type I2 = Includes<[2, 3, 3, 1], 1> // true
考察知识点
解法一
数组转换成联合类型
type Includes<T extends Array<any>, E> =
E extends T[number] ?true :false
type I0 = Includes<[], 1> // false
type I1 = Includes<[2, 2, 3, 1], 2> // true
type I2 = Includes<[2, 3, 3, 1], 1> // true
小结:知道 array[number]这个技巧,这题就很简单了,将数组转换成联合类型,再进行约束。
解法二
利用递归,逐一比较,退出条件为发现相同,和对比完毕
type IsEqual<A, B> = A extends B? B extends A ? true :false :false
type Includes<T extends Array<any>, E> =
T extends[first : infer A , ...rest :infer B ]
?IsEqual<A ,E> extends true
?true
:Includes<B,E>
: false
type I0 = Includes<[], 1> // false
type I1 = Includes<[2, 2, 3, 1], 2> // true
type I2 = Includes<[2, 3, 3, 1], 1> // true
小结:
- 首先定义一个判断是否相等的方法。
- 如果入参为空数组则比对失败,返回false。
- 然后用 infer 取出数组的第一项和指定类型作比较,成功返回true,失败则将剩余参数作为入参递归比较。
该解法的思路重点在于递归的结束条件,成功结束,比对数组为空结束。
第二题
实现一个 UnionToIntersection 工具类型,用于把联合类型转换为交叉类型。具体的使用示例如下所示:
type UnionToIntersection<U> = // 你的实现代码
// 测试用例
type U0 = UnionToIntersection<string | number> // never
type U1 = UnionToIntersection<{ name: string } | { age: number }>
// { name: string; } & { age: number; }
考察知识点
利用函数参数类型逆变,从而实现了联合类型到交叉类型的转变,当函数的参数是联合类型,会转变为交叉类型
题解:
// 实现一个 UnionToIntersection 工具类型,用于把联合类型转换为交叉类型。具体的使用示例如下所示:
type UnionToIntersection<U> = (U extends U ?
(arg: U) => any: never) extends (arg: infer T) => any
? T
: never;
// 测试用例
type U0 = UnionToIntersection<string | number> // never
type U1 = UnionToIntersection<{ name: string } | { age: number }> // { name: string; } & { age: number; }
小结:
把 入参作为 函数参数,然后用 infer 将值取出即可