[2] 工具类型

87 阅读3分钟

TypeScript提供了一些非常好用的工具类型,能够配合我们更好的使用工具类型。

type 定义类型

类型别名:

type NumberOrString = number | string; // 定义类型
const name: NumberOrString = 'lichuyan';

keyof & typeof

keyof A : 返回A类型的所有key,组成联合类型。
typeof 变量: 得到变量B的类型,例如是A。
type AType = keyof typeof Data。得到D变量类型的所有key的联合类型。

[P in Keys] 映射类型

遍历key

type Keys = 'option1' | 'option2';
type Flags = { [K in Keys]: boolean };

等价于

type Flags = {
    option1: boolean;
    option2: boolean;
}

T[K]索引访问操作符

// 要确保类型变量 K extends keyof T
function getProperty<T, K extends keyof T>(o: T, name: K): T[K] {
    return o[name]; // o[name] is of type T[K]
}

Record

Record 能够快速创建对象类型。 使用方式Record<K, V>,能够快速的为object创建统一的key和value类型。

image.png 因为V是string类型,但是age的值为number了。

Pick & Omit

针对interface

Pick:主要作用是从一组属性中拿出某个属性,并将其返回。--挑选属性
Omit:主要作用是从一组属性中排除某个属性,并将排除属性后的结果返回。--排除属性

Pick

interface选取部分属性生成新type。

{
    interface User {
    name:string;
    address:string;
}
type NameOnlyUser = Pick<User,'name'>;
let user: NameOnlyUser = {
    name: 'lichuyan'
}

Omit<T, K extends keyof any>

注意:Omit<T, K> = Pick<T, Exclude<keyof T, K>>

用于剔除interface中的部分属性,生成新的type(类型)。

interface User {
    name:string;
    address:string;
}
type UserWithoutName = Omit<User, 'name'>; // 从User中去除,name属性。 去除多个,"name"| "address"
let user: UserWithoutName = {
}

Exclude & Extract

针对联合类型的操作

  • Exclude:从一个联合类型中排除掉属于另一个联合类型的子集
  • Extract:跟Exclude相反,从从一个联合类型中取出属于另一个联合类型的子集

Exclude(排除)

Exclude使用形式是Exclude<T, S>,如果T中的属性在S不存在那么就会返回。

接口 - keyof 可以用来取得一个对象接口的所有 key 值.
interface User {
    name: string;
    address: string;
    order_date: string
}
interface User1 {
   name: string;
   odd: string
}

type OnlyAddress = Exclude<keyof User, keyof User1>; // name| address | order_date    name | odd   =   address | order_date

Extract(排除)

举一反三,如果Exclude是取差集,那么Extract就是取交集。会返回两个联合类型中相同的部分

interface A {
    show: boolean,
    hidden: boolean,
    status: string
}

interface B {
    show: boolean,
    name: string
}

type outPut = Extract<keyof A, keyof B>

image.png

实践经验

(1) 尽量减少重复代码

interface Person {
      firstName: string;
      lastName: string;
}
interface PersonWithBirthDate {
      firstName: string;
      lastName: string;
      birth: Date;
}

相对于 Person 接口来说, PersonWithBirthDate 接口只是多了一个 birth 属性,其他的属性跟 Person 接口是一样的。那么如何避免出现例子中的重复代码呢?要解决这个问题,可以利用extends 关键字。

interface Person {
      firstName: string;
      lastName: string;
}
interface PersonWithBirthDate extends Person {
      birth: Date;
}

(2) 提高类型复用性,放到types文件里,export出去

// ./src/model/user.ts
export interface userReq {
    username: string
    password: string
}

export interface userRes {
    nickname: string
    avatar?: string
    age: number
}

(3) 高级小技巧

ST
接口A、B一样多type B = A
A少、B多interface B extends A { XXX: string // 新添加的 } 或type C = A && B (交叉类型,A和B的并集)
A多、B少type B = Pick<A, 'name'>; // 从A中选择一些 或 type B = Omit<A, 'name'>; // 从A中抛弃一些