【问题标题】:Accurate types for a lookup of values of a string enum in TypeScript在 TypeScript 中查找字符串枚举值的准确类型
【发布时间】:2019-09-13 11:24:03
【问题描述】:

假设我有这个字符串枚举:

enum Color {
    None = "Q",
    Red = "R",
    Green = "G",
    Blue = "B",
}

现在,在 TypeScript 中,string enums have no reverse mappings,所以我不能写Color["Q"] 来获得潜在的Color。我尝试声明自己的辅助函数:

type StringEnum = {[key: string]: string};
function lookup<E extends StringEnum>(stringEnum: E, s: string): keyof E | undefined {
    for (const enumValue of keysOf(stringEnum)) {
        if (stringEnum[enumValue] === s) {
            return enumValue;
        }
    }
    return undefined;
}

keysOf 存在

function keysOf<K extends {}>(o: K): (keyof K)[];
function keysOf(o: any) { return Object.keys(o); }

...但实际上,我不知道返回类型应该是什么。这是为了编译,但不是:

const color: Color = lookup(Color, "Q") || Color.None;

因为lookup 函数的返回类型现在是"None" | "Red" | "Green" | "Blue" | undefined 而不仅仅是Color | undefined

能在保留类型信息的同时很好的解决这个问题吗?

【问题讨论】:

    标签: typescript enums


    【解决方案1】:

    您的lookup 函数返回一个枚举字符串key,但您也提供枚举 Color.None 作为短路,以防lookup 返回未定义。所以这里的类型不匹配。

    一般来说,字符串枚举键可以像this这样输入:

    type ColorKeys = keyof typeof Color // "None" | "Red" | "Green" | "Blue"
    const blueKey: keyof typeof Color = "Blue" 
    

    如果你写const blueValue = Color.None,变量blueValue 保存的是枚举字符串值"Q",而不是文字"None"。所以我们可以通过以下方式修复const color的赋值:

    const color = lookup(Color, "Q") || "None";
    // or with explicit type
    const color: keyof typeof Color = lookup(Color, "Q") || "None";
    

    枚举类型cannot have an index signature,所以我在这里输入StringEnum{[key: string]: any} 以使其编译。

    Playground

    更新:从lookup 获取键入的枚举值

    如果您想将一个未缩小的字符串值传递给lookup,并将其作为缩小的枚举值类型(如果存在)返回(否则为undefined),您可以按照与第一个示例类似的方式进行操作:

    function lookup<E extends StringEnum>(
      stringEnum: E,
      s: string
    ): E[keyof E] | undefined {
      for (const enumKey of keysOf(stringEnum)) {
        if (stringEnum[enumKey] === s) {
          // here we have to help the compiler
          return stringEnum[enumKey] as E[keyof E];
        }
      }
      return undefined;
    }
    
    // let's test it
    const look = lookup(Color, "Q") // const look: Color | undefined
    
    // for further understanding
    type AllColorKeys = keyof typeof Color // = "None" | "Red" | "Green" | "Blue"
    type AllColorValues = (typeof Color)[keyof typeof Color] // = Color
    type IsColorSuperType = Color.Blue extends Color ? true: false // = true
    

    Color枚举的情况下,返回的lookup type将返回值Q,类型为Color | undefined,作为所有可能的Color枚举值Color.NoneColor.Red等的联合on 将是超类型Color。定义的枚举结构本身具有typeof Color 类型,与static and instance side of a class 相当。

    Playground

    【讨论】:

    • 非常感谢!是的,这行得通——但它实际上与我想要的相反。我希望我的查找函数返回枚举值,但我不知道如何键入它以获得取决于我传递的枚举的精确类型。我不知道您提供的链接是否表明这实际上是不可能的。
    • 不知道,如果我理解正确的话:您的lookup,正如您在问题中定义的那样,返回枚举键(如forconst color,它保存枚举键“无”) .然后你可以写const result = Color[color],结果将包含你的枚举值“Q”,类型为Color。你也可以写const str: string = "None"; const result = Color[str as keyof typeof Color] 来从一个未变窄的字符串中获取值。
    • 实际上,我希望lookup 返回Color | undefined,具体取决于传递的参数是否是用于表示Color 的字符串值之一。
    • 太棒了! E[keyof E] 真的是我错过的部分。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2014-07-23
    • 2018-11-25
    • 1970-01-01
    相关资源
    最近更新 更多