如何从 Typescript 的接口中提取 "string" 属性 名称?

How to extract "string" property names from an interface in Typescript?

Typescript playground

我想从 SOME_OBJECT 中提取 string 属性并将其作为联合类型获取。因此,在下面的示例中,我希望 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"

这是我得到的:

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

我不太确定条件类型。我可能会在这里尝试使用的是 Pick 并且我会做类似

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

type ExtractString = Pick<SOME_OBJECT, "title" | "label">;

type STRING_KEYS = ExtractString

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>

Typescript playground

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


更新(如何运作)

我研究了更多以了解代码的实际作用,我想我已经弄明白了。

我将其分为两步:

第 1 步

第一步,将创建一个新的object/type。

此新对象的键将与通用类型 T(示例中的 SOME_OBJECT)的键相同 K in keyof T

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

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

第 2 步

在这一步中,我们将简单地获取从 步骤 1 生成的对象,然后询问 通过 type STEP_2<T> = T[keyof T].

将其所有可能值打字稿 return

请记住,keyof T 表示 T 中所有属性的并集。因此,当与 keyof T 联合的成员一起调用时,Typescript 将 return 与 STEP_1_RESULT 对象的所有可能值的联合。

在我们的示例中,它将 return "title" | "label" | never | never | never

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