代码之家  ›  专栏  ›  技术社区  ›  Terry

在TypeScript中将字符串强制转换为枚举

  •  0
  • Terry  · 技术社区  · 7 年前

    在TypeScript中处理枚举时遇到了一个小问题。我的设想是:

    • 我定义了一个包含允许值的字符串枚举
    • string 类型),并必须将其强制转换到所述枚举

    value 通过这个方法,智能感知告诉我 价值 仍然是一种 一串 而不是枚举。我怎么能强迫你 价值 AllowedValues ?

    下面是一个概念验证示例:

    /** enum */
    enum AllowedValues {
        LOREM_IPSUM = 'lorem ipsum',
        DOLOR_SIT = 'dolor sir',
        AMET = 'amet'
    }
    
    /** @method */
    function doSomething(value: string = AllowedValues.LOREM_IPSUM) {
    
        // If value is not found in enum, force it to a default
        if (!(Object as any).values(AllowedValues).includes(value))
            value = AllowedValues.LOREM_IPSUM;
    
        // Value should be of type `AllowedValues` here
        // But TypeScript/Intellisense still thinks it is `string`
        console.log(value);
    }
    
    doSomething('amet');    // Should log `amet`
    doSomething('aloha');   // Should log `lorem ipsum`, since it is not found in `AllowedValues`
    

    你也可以在网上找到它 TypeScript playground .

    1 回复  |  直到 7 年前
        1
  •  1
  •   jcalz    7 年前

    这里发生了一些事情。一是TypeScript不明白这一点 Object.values(x).includes(y) 是一个 type guard y . 它与编译器试图缩小类型的内置方式不匹配,例如 typeof , instanceof ,或 in user-defined type guard 要表达这种检查方式:

    function isPropertyValue<T>(object: T, possibleValue: any): possibleValue is T[keyof T] {
      return Object.values(object).includes(possibleValue);
    }
    
    declare function onlyAcceptAllowedValues(allowedValue: AllowedValues): void;
    declare const v: string;
    if (isPropertyValue(AllowedValues, v)) {
      onlyAcceptAllowedValues(v); // v is narrowed to AllowedValues; it works!
    }
    

    function doSomething(value: string = AllowedValues.LOREM_IPSUM) {    
      if (!(isPropertyValue(AllowedValues, value)))
        value = AllowedValues.LOREM_IPSUM;
    
      // TypeScript/Intellisense still thinks it is `string`
      console.log(value);
    }
    

    哦,还是不行。


    第二件事是:如果你重新分配一个变量的值,TypeScript基本上放弃了它的缩小。编译器花了大量的精力来理解控制流对变量类型的影响,但是 it's not perfect 我们 AllowedValues.LOREM_IPSUM value 使之成为 AllowedValues ,编译器 gives up 并假定它是其原始的注释类型,即 string .

    处理问题的方法 允许值 . 最直接的方法就是让它成为 const 变量,如下所示:

    function doSomething(value: string = AllowedValues.LOREM_IPSUM) {    
      const allowedValue = isPropertyValue(AllowedValues, value) ? value : AllowedValues.LOREM_IPSUM;
      console.log(allowedValue);
    }
    

    allowedValue 推断为 允许值 价值 如果类型保护成功(在哪一点 价值 是一个 允许值 ),或 AllowedValues.LOREM\u IPSUM允许值 如果类型保护失败。不管怎样, 允许值 是一个 允许值


    如果你想帮助编译器理解一些东西的话,这就是我建议的修改。希望有帮助。祝你好运!