TS 中的一些高阶技巧

1. keyof 和 in

1.1 keyof

keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键

interface Point {
    x: number;
    y: number;
}

// type keys = "x" | "y"
type keys = keyof Point; 

假设有一个 object 如下所示,我们需要使用 typescript 实现一个 get 函数来获取它的属性值

const data = {
  a: 3,
  hello: 'world'
}

function get(o: object, name: string) {
  return o[name]
}

我们刚开始可能会这么写,不过它有很多缺点

  1. 无法确认返回类型:这将损失 ts 最大的类型校验功能
  2. 无法对 key 做约束:可能会犯拼写错误的问题

这时可以使用 keyof 来加强 get 函数的类型功能

function get<T extends object, K extends keyof T>(o: T, name: K): T[K] {
  return o[name]
}

1.2 in

in 则可以遍历枚举类型, 例如

type Keys = "a" | "b"
type Obj =  {
  [p in Keys]: any
} // -> { a: any, b: any }

keyof 产生枚举类型, in 使用枚举类型遍历, 所以他们经常一起使用, 看下 Partial 源码

type Partial<T> = { [P in keyof T]?: T[P] };

上面语句的意思是 keyof T 拿到 T 所有属性名, 然后 in 进行遍历, 将值赋给 P, 最后 T[P] 取得相应属性的值.

2. Required & Partial & Pick

type Required<T> = {
  [P in keyof T]-?: T[P];
};

type Partial<T> = {
  [P in keyof T]?: T[P];
};

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
};

interface User {
  id: number;
  age: number;
  name: string;
};

// 相当于: type PartialUser = { id?: number; age?: number; name?: string; }
type PartialUser = Partial<User>

// 相当于: type PickUser = { id: number; age: number; }
type PickUser = Pick<User, "id" | "age">

这几个类型已内置在 Typescript中

3. Condition Type

类似于 js 中的 三目 运算符,可以使用它扩展一些基本类型

T extends U ? X : Y

type isTrue<T> = T extends true ? true : false

// 相当于 type t = false
type t = isTrue<number>

// 相当于 type t = false
type t1 = isTrue<false>

4. Exclude

Exclude 将某个类型中属于另一个的类型移除掉。

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

平常日剔除休息日就是工作日

// 一周(平常日)
type Weekday = 'Monday' | 'Tuesday' | 'Wednesday' | 'Thursday' | 'Friday' | 'Saturday' | 'Sunday';
// 休息日
type DayOff = 'Saturday' | 'Sunday';
// 工作日
type WorkDay = Exclude<Weekday, DayOff>; 

const day: WorkDay = 'Monday';

5. Extract

和 Exclude 相反,提取共同的类型:

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

提取重叠的时间即可:

// 休息日
type DayOff = 'Saturday' | 'Sunday';
// 会员日
type VipDay = 'Sunday' | 'Monday';

// 等价与 type DoubleDiscountDay = 'Sunday';
type DoubleDiscountDay = Extract<DayOff, VipDay>;

const day0: DoubleDiscountDay = 'Sunday'; // Success
const day1: DoubleDiscountDay = 'Monday'; // Error

6.Omit

Pick 和 Exclude 进行组合, 实现忽略对象某些属性功能

type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

忽略某些属性,不显示:

interface PetInfo {
  name: string;
  age: string;
}

type NonVipInfo = Omit<PetInfo, 'age'>;

这个和 Pick 功能相反,当要隐藏的字段较少时,用 Omit 方便,当要显示的信息较少时,用 Pick 方便。

7.ReturnType

需求:小明的宠物平台越做越好,想要对接供应商平台,做到自动补货,清点。供应商给了一个函数 F 用于获取信息,并提示说由于他们升级接口,后续返回的数据格式可能会改变。小明想在升级接口时自动发现代码改动点,同步检查。

ReturnType:提取函数的返回类型,ts 原理如下:

type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;

小明可以这样实现:

import { F } from 'vendor';

type Res = ReturnType<F>;

function myFun(res: Res) {...}

在使用 ReturnType 之前,你可能这样做:

function a(): number {
  // ...
}

const res: number = a();

直接编码的坏处就是丢失了类型的依赖关系信息,number 类型是依赖于 a() 函数的,如果 a 的返回类型修改,res 的类型也应该修改,不然就埋下了一个定时炸弹,bug 指不准哪天就出现了。

8.NonNullable – 从T中剔除null和undefined。

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]
type T14 = ReturnType<typeof f1>;  // { a: number, b: string }
type T15 = ReturnType<any>;  // any
type T16 = ReturnType<never>;  // any
type T17 = ReturnType<string>;  // Error
type T18 = ReturnType<Function>;  // Error

9.InstanceType – 获取构造函数类型的实例类型。

class C {
    x = 0;
    y = 0;
}

type T20 = InstanceType<typeof C>;  // C
type T21 = InstanceType<any>;  // any
type T22 = InstanceType<never>;  // any
type T23 = InstanceType<string>;  // Error
type T24 = InstanceType<Function>;  // Error
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值