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

1,160 阅读2分钟

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

序言:

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

第一题

实现一个 Merge 工具类型,用于把两个类型合并成一个新的类型。第二种类型(SecondType)的 Keys 将会覆盖第一种类型(FirstType)的 Keys。具体的使用示例如下所示:

type Foo = { 
   a: number;
   b: string;
};
​
type Bar = {
   b: number;
};
​
type Merge<FirstType, SecondType> = // 你的实现代码
​
const ab: Merge<Foo, Bar> = { a: 1, b: 2 };

考察知识

  1. 交叉类型的应用
  2. 属性遍历的使用

解法一

  1. 先将第一种类型中和第二种类型中重复的属性删除,再用结果交叉第二种属性即可达到目的。
type Foo = { 
   a: number;
   b: string;
};
​
type Bar = {
   b: number;
};
​
type Merge<FirstType, SecondType> = Omit<FirstType, keyof SecondType> & SecondType
​
const ab: Merge<Foo, Bar> = { a: 1, b: 2 };

解法二

  1. 将两种类型交叉,得到所有属性
  2. 遍历所有属性进行判读,首先判断是否属于属性二,属于则使用属性二,否则使用属性一对应的属性。
type Foo = { 
   a: number;
   b: string;
};
​
type Bar = {
   b: number;
};
​
type Merge<FirstType, SecondType> = {
  [ P in keyof FirstType & SecondType] 
: P extends keyof SecondType? SecondType[P] 
: FirstType[P] 
}
const ab: Merge<Foo, Bar> = { a: 1, b: 2 };

第二题

实现一个 RequireAtLeastOne 工具类型,它将创建至少含有一个给定 Keys 的类型,其余的 Keys 保持原样。具体的使用示例如下所示:

type Responder = {
   text?: () => string;
   json?: () => string;
   secure?: boolean;
};
​
type RequireAtLeastOne<
    ObjectType,
    KeysType extends keyof ObjectType = keyof ObjectType,
> = // 你的实现代码// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
    json: () => '{"message": "ok"}',
    secure: true
};
​

考察知识

  1. Pick<T,V> (从 T 类型 挑选 V 类型)
  2. Required
  3. 交叉类型的应用
type Responder = {
   text?: () => string;
   json?: () => string;
   secure?: boolean;
};
​
type RequireAtLeastOne<
    ObjectType,
    KeysType extends keyof ObjectType = keyof ObjectType,
> = KeysType extends keyof ObjectType ?  ObjectType & Required< Pick<ObjectType,KeysType>>:never// 表示当前类型至少包含 'text' 或 'json' 键
const responder: RequireAtLeastOne<Responder, 'text' | 'json'> = {
    json: () => '{"message": "ok"}',
    secure: true
};//成立
const responder1: RequireAtLeastOne<Responder, 'text' | 'json'> = {
    text: () => '{"message": "ok"}',
    secure: true
};//成立
const responder2: RequireAtLeastOne<Responder, 'text' | 'json'> = {
    secure: true
};//报错

小结: 该题的解题思路就是将传入的联合类型,从目标对象中取出转换为必选,其他的不变。有一点让人疑惑的地方就是,全部转换为必选类型,为啥最后有一个就行,那是因为联合类型会分布运算。