搞定TS,就靠这个系列(十一)

911 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

序言

这是搞定 TS 第十篇,如果没有基础的小伙伴想要从零搞定 TS ,请从第一篇开始juejin.cn/post/701033…

第一题

实现一个 RemoveIndexSignature 工具类型,用于移除已有类型中的索引签名。具体的使用示例如下所示。

interface Foo {
  [key: string]: any;
  [key: number]: any;
  bar(): void;
}
​
type RemoveIndexSignature<T> = // 你的实现代码type FooWithOnlyBar = RemoveIndexSignature<Foo>; //{ bar: () => void; }

考察知识

  1. 索引类型的特征:索引类型的 key 只会设置为 string 和 number 。
  2. as 关键字的使用。

题解

interface Foo {
  [key: string]: any;
  [key: number]: any;
  bar(): void;
}
type RemoveIndexSignature<T> = {
  [P in keyof T as string extends P ? never : number extends P?never:P] :T[P]
}
​
type FooWithOnlyBar = RemoveIndexSignature<Foo>; //{ bar: () => void; }

小结: 我们遍历所有key,然后用 as 将 number 和 string 类型的key 过滤掉。 ​

第二题

实现一个 Mutable 工具类型,用于移除对象类型上所有属性或部分属性的 readonly 修饰符。具体的使用示例如下所示。

type Foo = {
  readonly a: number;
  readonly b: string;
  readonly c: boolean;
};
​
type Mutable<T, Keys extends keyof T = keyof T> = // 你的实现代码const mutableFoo: Mutable<Foo, 'a'> = { a: 1, b: '2', c: true };
​
mutableFoo.a = 3; // OK
mutableFoo.b = '6'; // Cannot assign to 'b' because it is a read-only property.

考察知识

  1. 如何将不可修改变为可修改。
  2. Omit<T , V> 的使用(从T 里面取出除了 V 的所有类型)。

题解

type Foo = {
  readonly a: number;
  readonly b: string;
  readonly c: boolean;
};
​
type Mutable<T, Keys extends keyof T = keyof T> ={
-readonly [ P in Keys ] : T [P] } & Omit<T,Keys>  
​
const mutableFoo: Mutable<Foo, 'a'> = { a: 1, b: '2', c: true };mutableFoo.a = 3; // OK
mutableFoo.b = '6'; // Cannot assign to 'b' because it is a read-only property.

小结:首先将 要可更改的类型遍历key ,定义为可更改,去原来的属性中取类型,剩下不变的属性用 Omit 取出,然后两个类型交叉一下,就得到答案了。

第三题

实现一个 IsUnion 工具类型,判断指定的类型是否为联合类型。具体的使用示例如下所示

type IsUnion<T, U = T> = // 你的实现代码type I0 = IsUnion<string|number> // true
type I1 = IsUnion<string|never> // false
type I2 =IsUnion<string|unknown> // false

考察知识

  1. 联合类型的分发特性,当联合类型作为泛型的时候,会触发分发特性
  2. 当 联合类型用 [ ] 包装以后,会失去分发特性

题解:

type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false :true :nevertype I0 = IsUnion<string|number> // true
type I1 = IsUnion<string|never> // false
type I2 =IsUnion<string|unknown> // false

相信很多小伙伴看到这个答案的时候一脸懵逼,没错,我当时也是,所以我们看下面的分解图

//假设输入的是联合类型
T extends U  是分布式条件类型 a  extends a | b  b extends a | b[U] extends [T] 因为 T 在前面已经展开了,所以我们要把[U]放前面,
[a]  extends [a|b][b] extends [a | b]
所以,当为联合类型时,判断不通过返回 true
​
​