题目
实现一个类型工具 MyExclude<T,U>,从联合类型T中排除U的类型成员,构造出一个新的类型。
例如:
// 把类型 'a' 从 'a'|'b'|'c' 中剔除,得到联合类型 'b'|'c'。
type t1 = MyExclude<'a' | 'b' | 'c', 'a'>
// 得到类型 'c'
type t2 = MyExclude<'a' | 'b' | 'c', 'a' | 'b'>
// 得到联合类型 string | number
type t3 = MyExclude<string | number | (() => void), Function>
原题链接
思路
类比 JavaScript
类比 JavaScript,就是实现一个函数:
这个函数接收 2 个数组,一个是源数组,一个是剔除数组,将剔除数组中的所有元素,从源数组中剔除掉,返回剔除元素后的源数组。
function MyExclude(sources, excludes) {
const rest = [];
sources.forEach(s => {
if (!excludes.includes(s)) {
rest.push(s);
}
});
return rest;
}
提取逻辑点
1. 遍历源数组,筛选出不在`剔除数组`中的元素,组成一个新数组返回
再把逻辑点翻译成 TypeScript 即可。
翻译成 TypeScript
用 typescript 实现上述逻辑点如下。
遍历源数组,筛选出不在剔除数组中的元素,组成一个新数组返回
创建1 个新的联合类型R,通过 T extends U 遍历 T 这个 联合类型,遍历到的每个类型都在 U 中检查一次,如果找得到就不要(返回never),如果找不到才要(返回T,也就是放入R中),最终返回 R。
type Exclude<T,U> = T extends U ? never : T;
extends 遍历+对比的过程:
T: a | b | c
U: a
1. 用 T 的 a, b, c 依次对比 U 的 a
a,a ==> a可以赋值给a,得到 never(空值,不放R中)
b,a ==> b不可以赋值给a,得到 T, 也就是把 b 放入 R
c,a ==> c不可以赋值给a,得到 T,也就是把 c 放入 R
2. 返回 R, 结果是 b | c
实现
综上所述,最终的类型工具 MyExclude 实现为:
type MyExclude<T,U> = T extends U ? never : T;