繁体   English   中英

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

[英]Casting strings to enum in TypeScript

在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操场上找到它。

这里发生了一些事情。 一个是打字稿不明白, Object.values(x).includes(y)是一种类型的后卫y 它与编译器尝试缩小类型(例如typeofinstanceofin checks)的内置方式不匹配。 为了帮助编译器,您可以使用用户定义的类型防护来表示这种检查方式:

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本质上放弃了它的范围缩小。 编译器付出了相当大的努力来理解控制流对变量类型的影响,但这并不完美 因此,即使我们知道将AllowedValues.LOREM_IPSUM分配给value使其成为AllowedValues ,编译器AllowedValues 放弃并假定它是其原始的带注释类型,即string

处理此问题的方法是创建一个新变量,编译器将其理解为除AllowedValues任何AllowedValues 最简单的方法是使其成为const变量,如下所示:

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

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


因此,如果您想帮助编译器理解事情,那将是我建议的更改。 希望能有所帮助。 祝好运!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM