首页 > 解决方案 > 如何从 Typescript 中的接口中提取“字符串”属性名称?

问题描述

打字稿游乐场

我想从中提取string属性SOME_OBJECT并将其作为联合类型获取。因此,在下面的示例中,我希望STRING_KEYS是类型 "title" | "label"

interface SOME_OBJECT {
    title:      string,
    label:      string,
    someBool:   boolean,
    someDate:   Date,
    someNumber: number
}

type ExtractString<T> = keyof T extends string ? keyof T : never;

type STRING_KEYS = ExtractString<SOME_OBJECT>  // <----- THIS SHOULD BE "title" | "label"

这就是我得到的:

在此处输入图像描述

我认为我在这里的方向是正确的(通过使用条件类型),但我还没有安静下来。实现这一目标的最佳方法是什么?

标签: typescripttypescript-typingsconditional-types

解决方案


Typescript Docs: Distributive Conditional Types下面的例子中得到了这个想法

在此处输入图像描述

所以我已经适应了它,它的工作原理:

interface SOME_OBJECT {
    title:      string,
    label:      string,
    someBool:   boolean,
    someDate:   Date,
    someNumber: number
}

type ExtractStringPropertyNames<T> = {
    [K in keyof T]: T[K] extends string ? K : never
}[keyof T]

type STRING_KEYS = ExtractStringPropertyNames<SOME_OBJECT>

在此处输入图像描述

打字稿游乐场

如果可能的话,我仍然有兴趣看到其他方法。特别是如果有更直接的方法,因为我认为这个答案感觉像是“黑客”,因为它并不能很清楚地说明代码在做什么。


更新(如何工作)

我已经研究了更多以了解代码实际上在做什么,我想我已经弄清楚了。

我把它分成两个步骤:

步骤1

在第一步中,将创建一个新的对象/类型。

这个新对象K in keyof T的键将与通用类型的键相同TSOME_OBJECT在示例中)。

对于这些键的值,我们将检查泛型类型T,如果这些属性的值是K扩展的string。这意味着这些值可以分配给string. 例如:string,"some_hard_coded_string_type"并且any都会通过测试。

对于通过测试的每个属性,我们将重复其键K名作为它们的值,否则将通过neverSTEP_1_RESULT您可以在下面看到结果。

在此处输入图像描述

第2步

在这一步中,我们将简单地获取从步骤 1生成的对象,并要求 Typescript 返回其所有可能的值,方法是type STEP_2<T> = T[keyof T].

请记住,它keyof T表示来自 的所有属性的并集TSTEP_1_RESULT因此,当与联合成员一起调用时,Typescript 将返回一个包含对象所有可能值的keyof T联合。

在我们的示例中,它将返回"title" | "label" | never | never | never.

但是由于never类型在联合类型中没有意义,所以这些值被丢弃,我们只剩下"title" | "label".

在此处输入图像描述


推荐阅读