如何在 TypeScript 中获取值为指定类型的对象的键

图片

TypeScript 中一个常见的问题是,当你想获取一个对象的键值时,该对象的值是给定的类型,例如,假设你有一个这样的对象:

type Obj = {  a: string;  b: string;  c: number;  d: number;}; 


我们只想检索值为  string  的键,所以我们想得到  "a" | "b" 。

这看起来很棘手,但让我们试一试。


快速解决方案
 

这种技术使用键重映射来只提取字符串键:

图片

你可以提供一个通用的条件来让它可重用:

图片

解释
 

让我们看看我是如何得出这个解决方案的,我会试着带你走过我的思考过程。

如果你把这些泛型类型看作有开头、中间和结尾,那么它们就更容易理解。

在开始时,我们从一个简单的对象开始。

type Obj = {  a: string;  b: string;  c: number;  d: number;};


我们知道我们正在朝向键的 union 方向前进,所以我们知道  keyof  将被包含在某个地方:

type KeysOfObj = keyof Obj;// 'a' | 'b' | 'c' | 'd'

你可能会想,太棒了,我们已经完成了一半,现在我们需要做的就是排除没有字符串值的键,也许可以使用  Exclude  类型的帮助器:

图片

当我们尝试填充  Exclude  的第二个类型参数时,问题变得明显起来,我们需要当前键的上下文来确定  Obj[Key]  是否是一个字符串。

所以我们类型的“中间”将是关于遍历每个键。整个故事很清楚——让我们实现它。


遍历每个键
 

有几种不同的方法可以实现这个目标,我最喜欢的是使用IIMT——即立即索引映射类型

type Obj = {  a: string;  b: string;  c: number;  d: number;};
type KeysOfObj = {  // ^?  [K in keyof Obj]: `hello_${K}`;}[keyof Obj];


这让我们可以使用映射类型创建一个对象,然后使用  keyof Obj  索引到它,以输出我们创建的对象的值。

这样做的好处是,我们可以访问当前键和同一作用域中的对象,因此我们可以使用当前键来索引对象。

在本例中,我们使用它创建一个字符串字面量类型,每个键都带有  hello_  前缀。

但是如果我们想根据值的类型做一些不同的事情呢?

条件类型
 

我们可以使用条件类型来完成这项工作。条件类型允许你用条件表达if/else逻辑:

type Obj = {  a: string;  b: string;  c: number;  d: number;};
type Tests = [  // ^?  Obj["a"] extends string ? true : false,  Obj["b"] extends string ? true : false,  Obj["c"] extends string ? true : false,  Obj["d"] extends string ? true : false];


在本例中,我们检查当前键的值是否为字符串,如果不是,则返回  never ,而不是  false 。

图片

你会注意到,从技术上讲, KeysOfObj  的类型应该是  'a' | 'b' | never | never :

type Obj = {  a: string;  b: string;  c: number;  d: number;};
type Tests = [  // ^?  Obj["a"] extends string ? "a" : never,  Obj["b"] extends string ? "b" : never,  Obj["c"] extends string ? "c" : never,  Obj["d"] extends string ? "d" : never];

但是 TypeScript 会自动从联合中移除  never ,所以我们最终得到的是  'a' | 'b' 。

图片


使其通用
 

最后的挑战是将这个转换为一个可以用于任何对象的类型帮助器,我们可以通过给  StringKeys  添加一个类型参数并删除对  Obj  的硬编码引用来实现:

图片

为了让它更具可重用性,我们可以给助手函数添加第二个类型参数,以便指定条件:

图片

我们已经找到了我们的类型帮助器,我们接收一个对象,通过IIMT来遍历它的键,并使用条件类型来检查当前键的值是否与条件匹配。
 

  欢迎关注公众号:文本魔术,了解更多

  • 27
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值