jtwang7 / JavaScript-Note

JavaScript学习笔记
10 stars 2 forks source link

TS 类型表达常用关键字 #64

Open jtwang7 opened 2 years ago

jtwang7 commented 2 years ago

TS 类型表达常用关键字

参考文章:TS 类型表达中常用的关键字

typeof

用于获取一个变量上的类型

const value = {
    a: '2',
    b: 5,
    c: {
        d: true,
    }
}

typeof value
// 结果如下:
// {
//  a: string,
//  b: number,
//  c: {
//      d: boolean,
//  }
// }

keyof

keyof 是TS中的索引类型查询操作符。keyof T 会得到由 T 上已知的公共属性名组成的联合类型。

interface Person {
    name: string;
    age: number;
    phoneNum: number;
}

type PersonProperty = keyof Person;

// type PersonProperty = "name" | "age" | "phoneNum"

keyof 在我们限制类型或者枚举属性时还是非常常见的,比如下面这个小例子:

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

当我们尝试获取不在目标对象上的属性值时,TS会为我们检查到这样简单的错误

T[K] 在TS里称作索引访问操作符(indexed access operator)。它可以为我们准确解析目标对象上的对应属性的正确类型。

简单理解就是 typescript 里的索引,获取的是 type 类型

in

in 操作符用于遍历目标类型的公开属性名。类似 for .. in 的机制, in 可用于联合类型或者枚举类型。

enum Letter {
    A,
    B,
    C,
}

type LetterMap = {
    [key in Letter]: string;
}

// type LetterMap = {
//     0: string;
//     1: string;
//     2: string;
// }
type Property = 'name' | 'age' | 'phoneNum';

type PropertyObject = {
    [key in Property]: string;
}

// type PropertyObject = {
//     name: string;
//     age: string;
//     phoneNum: string;
// }

利用可用于联合类型的特性,我们有下面这种很常见的做法(仅举例):

type ToString<T> {
    [key in keyof T]: string;
}
jtwang7 commented 2 years ago

获取对象键值对的类型定义

获取键的类型定义

const obj = {
  a: 123,
  b: true,
} as const

type Key = keyof (typeof obj)

封装为 KeyOf

type KeyOf<T> = keyof T

获取值的类型定义

const obj = {
  a: 123,
  b: true,
} as const

type Value = (typeof obj)[keyof (typeof obj)]

封装为 ValueOf:

type ValueOf<T> = T[keyof T]
jtwang7 commented 1 year ago

Expand

引用文章: TS类型展开

使用场景:Why use Expand ?

在 TS 类型中,我们进行类型的调用,有时会不显示对应的结果,只显示相关类型的调用。在书写代码时,我们也会经常碰到 IDE 只解析别名类型,导致明明输入的类型是正确的,但仍给你报错信息。

// 想要显示:boolean | number | string
// IDE 实际显示:string | CxrObject
type unionCase = CxrObject | string

解决方法

✅ 利用 extendsinfer 关键字对其进行判断后返回,即可展开

type Expand<T> = T extends infer O ? O : never
type r1 = Expand<keyofTest> // "name" | "age"

❇️ 当我们遇到对象类型时,需要进一步处理

type Expand<T> = T extends infer O 
    ? {[K in keyof O]: O[K]} 
    : never
type r3 = Expand<unionCase> // type r3 = string | { age: number; }

❇️ 如果传入的参数中有对象嵌套,需要做一层递归逻辑判断

type Expand<T> = T extends object 
  ? T extends infer O 
    ? {[K in keyof O]: Expand<O[K]>}
    : never
  : T
type r5 = ExpandRecursive<obj11> // { c: { age: number; }; name: string; }

🔥 Expand 封装

type Expand<T> = T extends object 
  ? T extends infer O 
    ? {[K in keyof O]: Expand<O[K]>}
    : never
  : T

缺陷:如果对象内嵌套了联合类型,那么就没办法正常展开,例如以下情况:

type CxrUnion = boolean | number
type obj11 = {
c: CxrUnion // 对象中的 union 无法展开(但是单纯的union可以展开)
name: string
}