TypeScript类型体操挑战(二)

314 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

简单

Exclude

挑战要求

在线示例

type MyExclude<T, U> = T extends U ? never : T;

当联合类型作用于泛型的时候,会将每一个类型都分布到该条件判断中。

例如:

type T = MyExclude<"a" | "b" | "c", "a">;

// 执行时大概是这样:
"a" extends "a" ? never : "a" |
"b" extends "a" ? never : "b" |
"c" extends "a" ? never : "c" 

// 所以最后 T 的类型就是
type T = "b" | "c"

查阅官方文档请参考分配条件类型

Awaited

挑战要求

在线示例

type MyAwaited<T> = T extends Promise<infer U> ? MyAwaited<U> : T;
  • 这个没啥好说的,就是通过条件判断加infer去进行推断
  • 需要注意下递归处理

If

挑战要求

在线示例

type If<C extends boolean, T, F> = C extends true ? T : F;
  • 这个也没啥好说的,就是利用条件判断

Concat

挑战要求

在线示例

type Concat<T extends any[], U extends any[]> = [...T, ...U];
  • 因为数组可以拥有rest元素,详情请看官方文档

Includes

挑战要求

在线示例

// 判断两个类型是否相等
type Equals<X, Y> = 
  (<T>() => T extends X ? 1 : 2) extends (<T>() => T extends Y ? 1 : 2)
  ? true
  : false;

type Includes<T extends readonly any[], U> = 
  T extends [infer F, ...infer R] 
  ? Equals<F, U> extends true
    ? true : Includes<R, U>
  : false;

首先来看下Equals类型,可以这么来理解,我通过了一些步骤来演进代码:

type Equals<X, Y> = X extends Y ? true : false;

type T = Equals<true, boolean>;

上面代码中,T的类型会为true,因为boolean类型兼容true类型。

type Equals<X, Y> = (() => X) extends (() => Y) ? true : false;

type T = Equals<true, boolean>;

上面代码中,T的类型还是true,函数的参数和返回值也是存在兼容的,道理和第一个一样的。

所以最后就成这样了:

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

要把括号括起来的看做是一个整体,一个定义好的类型,例如(<T>() => T extends X ? 1 : 2),所以这时使用extends进行判断的时候,检查会要求类型定义一致,所以就能判断出类型是否相等了。

挑战里测试用例用到的Equal也是这么来判断的。

这时来看看Includes类型,应该好理解很多了。

就是获取数组的第一个元素类型,然后对比是否相等,然后通过递归的方式,把数组中的每一个元素类型都对比了一遍。

答案参考自解答区,然后根据自己的理解,来解释了下,要是有问题,还请大佬们指点一下。