Unique
挑战
实现类型版本 Lodash.uniq()
。Unique<T>
接收一个数组 T
,返回去重后的列表。
type Res = Unique<[1, 1, 2, 2, 3, 3]>; // expected to be [1, 2, 3]
type Res1 = Unique<[1, 2, 3, 4, 4, 5, 6, 7]>; // expected to be [1, 2, 3, 4, 5, 6, 7]
type Res2 = Unique<[1, "a", 2, "b", 2, "a"]>; // expected to be [1, "a", 2, "b"]
解答
在这个挑战中,我们需要在类型系统中实现 lodash 的 .uniq()
函数。我们必须接受一
个元组类型参数,过滤到重复的元素,只保留唯一的元素集合。
让我们从初始类型开始:
type Unique<T> = any;
为了检测元素在元组中是否是唯一的,首先我们需要读取它。要做到这一点,我们将在条件 类型中推断它。
不过,为了得到预期的结果,我们需要按照相反的顺序进行。如果我们通过
[infer H, ...infer T]
的方式,我们的结果的顺序将会是错的。因此我们先取得最后的
元素,将其它的元素放在其头部:
type Unique<T> = T extends [...infer H, infer T] ? never : never;
现在我们得到了元素 T
,我们应该检测什么呢?我们需要检测元素 T
是否存在于元组
的其余部分(头部)中:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? never
: never
: never;
通过条件类型 T extends H[number]
,我们可以检测类型 T
是否存在于 H
中。如果
存在则意味着重复,我们需要跳过它。也就是说我们只返回头部元素:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: never
: never;
如果不存在于头部(H
)中,就说明它是唯一的。我们返回的元组需要包含它:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: [...Unique<H>, T]
: never;
最后一种情况是输入类型 T
与元组不匹配。这里我们只需要返回一个空元组,以避免在
递归调用中中断展开操作:
type Unique<T> = T extends [...infer H, infer T]
? T extends H[number]
? [...Unique<H>]
: [...Unique<H>, T]
: [];
这样,我们实现了一个可以返回唯一元素的类型。
评论