首页 文章

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

提问于
浏览
0

在使用TypeScript中的枚举时,我遇到了一个小问题 . 我的情况是这样的:

  • 我已经定义了一个包含允许值的字符串枚举

  • 我已经定义了一个接受任何传入值( string 类型)的方法,并且必须将它强制转换为所述枚举

问题是,即使在检查来自方法的传入 value 之后,intellisense告诉我 value 仍然是 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 回答

  • 1

    这里有一些事情发生 . 一个是TypeScript不理解 Object.values(x).includes(y)y 上是type guard . 它与编译器尝试缩小类型的内置方式不匹配,例如 typeofinstanceofin 检查 . 为了帮助编译器,你可以使用_3001105来表达这种检查方式:

    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 .

    处理这个的方法是创建一个新的变量,编译器理解它永远不会是 AllowedValues . 最直接的方法是使它成为 const 变量,如下所示:

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

    在上面,新变量 allowedValue 被推断为 AllowedValues ,因为如果类型保护成功(此时 valueAllowedValues )它被设置为 value ,或者如果类型保护失败则设置为 AllowedValues.LOREM_IPSUM . 无论哪种方式, allowedValue 都是 AllowedValues .


    如果你想帮助编译器理解事情,那么这将是我建议的更改 . 希望有所帮助 . 祝好运!

相关问题