挑战

在类型系统中实现 JavaScript 的Array.includes函数,接收 2 个参数。它的输出应该 是布尔类型truefalse。例如:

// expected to be `false`
type isPillarMen = Includes<["Kars", "Esidisi", "Wamuu", "Santana"], "Dio">;

解答

我们首先编写接受两个参数的类型:T(元组)和U(我们正在寻找的)。

type Includes<T, U> = never;

在我们真正能在元组中找到一些东西之前,将其“转换”为联合(union)比会元组(tuple) 更容易一些。为此,我们可以使用索引类型(indexed types)。如果我们访 问T[number],TypeScript 会返回T中所有元素的联合(union)。例如,如果你有一 个T = [1, 2, 3],通过T = [number]访问将返回1 | 2 | 3

type Includes<T, U> = T[number];

但是,这里有一个错误,“Type ‘number’ cannot be used to index type ‘T’”。这是因为 类型T没有约束。我们需要告诉 TypeScript,T是一个数组。

type Includes<T extends unknown[], U> = T[number];

我们有了元素的联合(union)。我们如何检查元素是否存在于联合(union)中?条件类型 分配(Distributive)!我们可以为联合(union)编写条件类型,TypeScript 会自动将条 件应用到联合(union)的每个元素上。

例如,如果你写2 extends 1 | 2,TypeScript 实际上会把它替换成 2 个条件语 句2 extends 12 extends 2

我们可以利用它检查U是否在T[number]中,如果在则返回 true。

type Includes<T extends unknown[], U> = U extends T[number] ? true : false;

参考