实现 Exclude

vortesnailLv.4
2024-09-02 12:00:14148
题目描述
实现内置的工具类型 Exclude<T, U>
,但不能使用它。其作用是从联合类型 T
中排除 U
的类型成员,返回一个新的类型。
例如:
// 得到联合类型 'movies' | 'books'。
type Result1 = MyExclude<'movies' | 'books' | 'games', 'games'>
// 得到类型 'movies'
type Result2 = MyExclude<'movies' | 'books' | 'games', 'books' | 'games'>
// 得到联合类型 string | number
type Result3 = MyExclude<string | number | (() => void), Function>
解题思路
根据题目的描述,直观的思路是,遍历 T
中的每一项,分别去检查在不在 U
的范围中,如果在就返回一个 never
,不在就返回当前遍历的项,最终返回新的联合类型。
先举个例子:
type Anis = 'dog' | 'cat'
type Cat = 'cat'
type IsIn = Cat extends Anis ? true : false // type IsIn = true
类似 JavaScript 中的三元表达式,在 TypeScript 中也能使用,上面的例子通过 extends
判断 Cat
是否在 Anis
的约束范围内,在就返回 true
,不在就返回 false
。
如何遍历 T
的每一项呢?巧妙的是,当条件类型作用于泛型类型时,它们在给定联合类型时变得具有分配性。要理解这句话我们直接看 Exclude
的实现:
type MyExclude<T, U> = T extends U ? never : T
type Anis = 'dog' | 'cat' | 'pig'
type Anis2 = 'cat' | 'horse'
type Result = MyExclude<Anis, Anis2> // type Result = 'dog' | 'pig'
上面执行 MyExclude<Anis, Anis2>
时等价于:
type Result = ('dog' extends Anis2 ? never : 'dog') |
('cat' extends Anis2 ? never : 'cat') |
('pig' extends Anis2 ? never : 'pig')
三个条件分支的返回值结合起来就是:
type Result = 'dog' | never | 'pig'
在 TypeScript 中,never
是所有类型的子类型,联合类型中直接可以忽略,所以最终结果就为:
type Result = 'dog' | 'pig'
解题步骤
通过以上的分析,理解了条件类型作用于泛型类型时具有分配性,本题就变得非常简单了。
type MyExclude<T, U> = T extends U ? never : T
完整代码:
/* _____________ 你的代码 _____________ */
type MyExclude<T, U> = T extends U ? never : T
/* _____________ 测试用例 _____________ */
import type { Equal, Expect } from '@type-challenges/utils'
type cases = [
Expect<Equal<MyExclude<'movies' | 'books' | 'games', 'games'>, 'movies' | 'books'>>,
Expect<Equal<MyExclude<'movies' | 'books' | 'games', 'books' | 'games'>, 'movies'>>,
Expect<Equal<MyExclude<string | number | (() => void), Function>, string | number>>,
]
总结
本题有一个非常重要的知识点,就是当条件类型作用于泛型类型时,它们在给定联合类型时变得具有分配性。extends
在常规当作约束类型使用时和在泛型中使用时是有区别的。
评论 0
0/1200
排序:
暂无评论,快成为第一个评论者吧~