在 TypeScript 中,如何获取其值属于给定类型的对象类型的键?

2023-12-15

我一直在尝试创建一个由 type 键组成的类型T其值为字符串。在伪代码中它将是keyof T where T[P] is a string.

我能想到的唯一方法是分两步:

// a mapped type that filters out properties that aren't strings via a conditional type
type StringValueKeys<T> = { [P in keyof T]: T[P] extends string ? T[P] : never };

// all keys of the above type
type Key<T> = keyof StringValueKeys<T>;

然而 TS 编译器说Key<T>简单地等于keyof T,即使我已经通过将其值设置为来过滤掉其值不是字符串的键never使用条件类型。

所以它仍然允许这样做,例如:

interface Thing {
    id: string;
    price: number;
    other: { stuff: boolean };
}

const key: Key<Thing> = 'other';

当唯一允许的值key确实应该是"id", not "id" | "price" | "other",因为其他两个键的值不是字符串。

链接到 TypeScript Playground 中的代码示例


有一个功能请求位于微软/TypeScript#48992原生支持这一点。不过,除非实现这一点,否则您可以通过多种方式制作自己的版本。

一种方法是与条件类型 and 索引访问类型, 像这样:

type KeysMatching<T, V> = {[K in keyof T]-?: T[K] extends V ? K : never}[keyof T];

然后取出属性匹配的键string像这样:

const key: KeysMatching<Thing, string> = 'other'; // ERROR!
// '"other"' is not assignable to type '"id"'

详细地:

KeysMatching<Thing, string> ➡

{[K in keyof Thing]-?: Thing[K] extends string ? K : never}[keyof Thing] ➡

{ 
  id: string extends string ? 'id' : never; 
  price: number extends string ? 'number' : never;
  other: { stuff: boolean } extends string ? 'other' : never;
}['id'|'price'|'other'] ➡

{ id: 'id', price: never, other: never }['id' | 'price' | 'other'] ➡

'id' | never | never ➡

'id'

请注意您在做什么:

type SetNonStringToNever<T> = { [P in keyof T]: T[P] extends string ? T[P] : never };

实际上只是转变非字符串属性values into never属性值。它没有触及按键。你的Thing会成为{id: string, price: never, other: never}。其按键与 的按键相同Thing。与此的主要区别是KeysMatching是你应该选择键,而不是值(所以P并不是T[P]).

Playground 代码链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 TypeScript 中,如何获取其值属于给定类型的对象类型的键? 的相关文章

随机推荐