如何从Typescript中的接口提取特定类型的所有字段的名称?

时间:2018-06-17 21:17:22

标签: typescript

我们说我有这样的界面:

interface SomeInterface {
    field1: string;
    field2: number;
    field3: string;
    field4: SomeOtherType;
}

我希望有一种类型可以提取所有键值是特定类型的键:

type ExtractFieldsOfType<Obj extends {}, Type> = // implementation

ExtractFieldsOfType<SomeInterface, string> // "field1" | "field3"
ExtractFieldsOfType<SomeInterface, number> // "field2"
ExtractFieldsOfType<SomeInterface, SomeOtherType> // "field4"

有可能写出这样的东西吗?我正在编写一个按键名操作对象的函数,但它只允许具有特定值的键。因此,通过类型系统来表达它是很好的。

1 个答案:

答案 0 :(得分:5)

您可以在TypeScript 2.8中使用条件类型。

我创建了支持类型AllowedFieldsWithType以实现更清晰的实施。

type AllowedFieldsWithType<Obj, Type> = {
    [K in keyof Obj]: Obj[K] extends Type ? K : never
};

type ExtractFieldsOfType<Obj, Type> = AllowedFieldsWithType<Obj, Type>[keyof Obj]

type StringFields = ExtractFieldsOfType<SomeInterface, string> // "field1" | "field3"
type NumberFields = ExtractFieldsOfType<SomeInterface, number> // "field2"
type ObjectFields = ExtractFieldsOfType<SomeInterface, SomeOtherType> // "field4"

它是如何工作的?

第一种类型:

type AllowedFieldsWithType<Obj, Type> = {
    [K in keyof Obj]: Obj[K] extends Type ? K : never
};

1)对于object中的每个字段,我们检查它是否扩展了Type,然后我们返回键的名称作为它的类型。如果不是(例如我们搜索string,但 field2 number类型 - 我们返回never。这是特殊类型,无法分配任何内容。

AllowedFieldsWithType<SomeInterface, String> equals to: {
  field1: 'field1';
  field2: never;
  field3: 'field3';
  field4: never;
}

2)然后我们必须过滤掉never属性,我们可以使用Pick来完成,但对于这个用例,我们只需要键名。

3)最终我们使用someType[keyof Obj]来收集给定类型的值,跳过永远不会。

我写了一篇深入解释这个主题的文章:Create a condition-based subset types