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

589 阅读2分钟

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

序言:

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

第一题

实现一个 OptionalKeys 工具类型,用来获取对象类型中声明的可选属性。具体的使用示例如下所示:

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};
​
type OptionalKeys<T> = // 你的实现代码
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

该题考察内容

  1. 可选属性的特征为指定属性 | undefined。所以我们从 undefined 出发即可。
  2. 筛选出符合条件的,将属性名赋值给类型名字,不符合的类型赋值为never,方便更改完成后取出的联合类型为结果。
  3. Exclude<T, U>。 将特定属性排除。

题解

type Person = {
  id: string;
  name: string;
  age: number;
  from?: string;
  speak?: string;
};
type OptionalKeys<T> = Exclude<{
    [P in keyof T ] : undefined extends T[P] ? P: never
}[keyof T] ,undefined>
​
​
type PersonOptionalKeys = OptionalKeys<Person> // "from" | "speak"

第二题

实现一个 Curry 工具类型,用来实现函数类型的柯里化处理。具体的使用示例如下所示:

type Curry<
  F extends (...args: any[]) => any,
  P extends any[] = Parameters<F>, 
  R = ReturnType<F> 
> = // 你的实现代码type F0 = Curry<() => Date>; // () => Date
type F1 = Curry<(a: number) => Date>; // (arg: number) => Date
type F2 = Curry<(a: number, b: string) => Date>; //  (arg_0: number) => (b: string) => Date

本题考察知识点

  1. Parameters 返回函数的参数
  2. ReturnType 返回函数的结果类型
  3. 函数柯里化

解题思路

柯里化的结束条件是参数只有一个的时候开始运算,所以我们把这个作为结束递归的条件

type Curry<
  F extends (...args: any[]) => any,
  P extends any[] = Parameters<F>, 
  R = ReturnType<F> 
> = P extends [first: infer A ,...rest: infer B ]
  ? B["length"] extends 0
  ? F :(arg:A)=>Curry<(...args: B)=> R
>: F
​
type F0 = Curry<() => Date>; // () => Date
type F1 = Curry<(a: number) => Date>; // (arg: number) => Date
type F2 = Curry<(a: number, b: string) => Date>; //  (arg_0: number) => (b: string) => Date

小结: 我们看上述步骤,首先我们将参数使用 infer 分离开了,然后判断参数数量是否是一个,是一个就开始执行,否则将剩余参数作为入参进行递归。