小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
序言
这是搞定 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; }
考察知识
- 索引类型的特征:索引类型的 key 只会设置为 string 和 number 。
- 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.
考察知识
- 如何将不可修改变为可修改。
- 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
考察知识
- 联合类型的分发特性,当联合类型作为泛型的时候,会触发分发特性
- 当 联合类型用 [ ] 包装以后,会失去分发特性
题解:
type IsUnion<T, U = T> = T extends U ? [U] extends [T] ? false :true :never
type 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