likes
comments
collection
share

TS-基于值的类型获取对象类型的属性

作者站长头像
站长
· 阅读数 44

前言

这回反过来操作,指定对象中属性的值类型,将值类型符合要求的属性更改为可选。Ts 中没有直接提供获取指定值类型的属性的方法,怎么去获取值为指定类型的属性,这是本文记叙的内容。

测试用的对象类型如下,获取其中值为 object 类型的属性名称:

type Human = {
  name: string
  age: number
  healthy: {
    illness: string
    status: string
  }
  occupation: {
    name: string
    workingHours: number
  }
}

代码

首先,肯定是通过值的类型去判断,有哪些属性值的类型是符合需求的,所以必定有 value extends valueType 的操作,用于判断值的类型是否符合要求。

而属性名称,说白了就是 string 的字面量类型而已,也是一个类型, 所以当条件符合时,可以直接将 key 作为属性的值类型赋予,而不符合时,将类型更改为 never

那么,可以写出如下代码:

// 接受两个泛型,T 为对象类型,valueType 为指定的对象类型
type PickByValueType<T extends object, valueType> = {
  // 判断值 T[key] 是否符合指定的类型
  // 如果符合,将该属性的值设置为 该属性名称的字面量类型,也就是 key
  // 否则,将属性的值设置为 never
  [key in keyof T]: T[key] extends valueType ? key : never
}

// 传入 Human 和 object
type PickByValueTypeHuman = PickByValueType<Human, object>

TS-基于值的类型获取对象类型的属性

可以看到,除了 occupationhealthy 之外,其他属性值的类型都变成了 never,而 occupationhealthy 的值类型变为了属性的名称。

接下来,可以通过取出所有属性的值类型,组成一个联合类型,在联合类型中,never 会被忽略掉,就只剩下 'occupation' | 'healthy',就是属性值为 object 的属性名称,这也是上面将不符合条件的属性值类型更改为 never 的原因。那要怎么把一个对象类型变成一个由值的类型组成的联合类型呢?

上面的 PickByValueTypeHuman 其实就是就是一个映射类型,则可以利用 PickByValueTypeHuman[key] 的方式取出其中某一个属性的值的类型:

// 取出其中 occupation 的值类型
type PickByValueTypeHuman = PickByValueType<Human, object>['occupation']

TS-基于值的类型获取对象类型的属性

// 取出其中 name 的值类型
type PickByValueTypeHuman = PickByValueType<Human, object>['name']

TS-基于值的类型获取对象类型的属性

可以看到通过,能够取出正确的值的类型,而访问的key 可以是一个联合类型,TS 会逐个遍历联合类型的中每一个属性名称,然后从映射类型中取出对应的值的类型,返回值的类型组成的联合类型:

type PickByValueTypeHuman = PickByValueType<Human, object>['occupation' | 'healthy' | 'name']

TS-基于值的类型获取对象类型的属性

PickByValueTypeHuman 变成了一个由值的类型组成的联合类型,而属性 name 的值类型为 never,在联合类型中会被忽略掉。

因此,可以直接访问全部的对象属性,就能得到所有值类型为指定类型的属性名称组成的联合类型,取值类型的操作,可以在 PickByValueType 完成,完整代码如下:

type PickByValueType<T extends object, valueType> = {
  [key in keyof T]: T[key] extends valueType ? key : never
}[keyof T] // 此处使用 keyof T 表示访问全部的对象属性

type PickByValueTypeHuman = PickByValueType<Human, object>

TS-基于值的类型获取对象类型的属性

至此,就是值的类型获取对象类型的属性的基本思路和原理了。

转载自:https://juejin.cn/post/7133060696744394788
评论
请登录