Skip to content

Unique

约 599 字大约 2 分钟

2022-12-01

题目

Github: Unique

实现类型版本的 Lodash.uniq 方法, Unique 接收数组类型 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"]
type Res3 = Unique<[string, number, 1, 'a', 1, string, 2, 'b', 2, number]> // expected to be [string, number, 1, "a", 2, "b"]
type Res4 = Unique<[unknown, unknown, any, any, never, never]> // expected to be [unknown, any, never]

解题思路

本挑战有两个难点:判断数组中是否包含某个元素;判断两个类型是否严格相等。

判断两个类型是否严格相等,请参考 类型系统的真假美猴王:破解 IsEqual<X, Y> 之谜

type Equal<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false

有了 Equal<X, Y> 类型工具,就可以实现 Include<T, U> 类型工具,判断数组 T 中是否包含元素 U

type Include<T extends unknown[], U> = T extends [infer F, ...infer O]
  ? Equal<F, U> extends true
    ? true
    : Include<O, U>
  : false

接下来,就可以实现 Unique<T> 类型工具,通过 条件类型 infer,从数组 T 中, 通过递归的方式从末尾取出一个个元素,判断是否严格等于类型 U

答案

type Equal<X, Y> =
  (<T>() => T extends X ? 1 : 2) extends
  (<T>() => T extends Y ? 1 : 2) ? true : false

type Include<T extends unknown[], U> = T extends [infer F, ...infer O]
  ? Equal<F, U> extends true
    ? true
    : Include<O, U>
  : false

type Unique<T extends unknown[],> = T extends [...infer O, infer F]
  ? Include<O, F> extends true
    ? Unique<O>
    : [...Unique<O>, F]
  : []

验证

type 
cases
= [
Expect
<
Equal
<
Unique
<[1, 1, 2, 2, 3, 3]>, [1, 2, 3]>>,
Expect
<
Equal
<
Unique
<[1, 2, 3, 4, 4, 5, 6, 7]>, [1, 2, 3, 4, 5, 6, 7]>>,
Expect
<
Equal
<
Unique
<[1, 'a', 2, 'b', 2, 'a']>, [1, 'a', 2, 'b']>>,
Expect
<
Equal
<
Unique
<[string, number, 1, 'a', 1, string, 2, 'b', 2, number]>, [string, number, 1, 'a', 2, 'b']>>,
Expect
<
Equal
<
Unique
<[unknown, unknown, any, any, never, never]>, [unknown, any, never]>>,
]

参考