简体   繁体   English

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

[英]Casting strings to enum in TypeScript

I've ran into a little issue when working with enums in TypeScript. 在TypeScript中使用枚举时,我遇到了一个小问题。 My scenario is this: 我的情况是这样的:

  • I have defined a string enum containing allowed values 我定义了一个包含允许值的字符串枚举
  • I have defined a method that accepts any incoming value (of string type), and have to cast it to the said enum 我定义了一个方法,该方法可以接受任何传入值( string类型),并将其强制转换为上述枚举

The problem is that even after checking if the incoming value from the method, intellisense tells me that value is still type of string instead of the enum. 问题是,即使检查了方法中的传入value ,intellisense仍告诉我该value仍然是string类型而不是枚举类型。 How can I force value to be a type of AllowedValues ? 如何强制将value设为AllowedValues类型?

Here is a proof-of-concept example: 这是一个概念验证示例:

/** 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`

You can also find it on TypeScript playground . 您也可以在TypeScript操场上找到它。

There are a few things going on here. 这里发生了一些事情。 One is that TypeScript doesn't understand that Object.values(x).includes(y) is a type guard on y . 一个是打字稿不明白, Object.values(x).includes(y)是一种类型的后卫y It doesn't match the built-in ways that the compiler tries to narrow types, such as typeof , instanceof , or in checks. 它与编译器尝试缩小类型(例如typeofinstanceofin checks)的内置方式不匹配。 To help the compiler out, you can use a user-defined type guard to express that way of checking: 为了帮助编译器,您可以使用用户定义的类型防护来表示这种检查方式:

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!
}

So let's first change your function to this: 因此,让我们首先将函数更改为此:

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);
}

Uh oh, still not working. 嗯,还是不行。


The second thing going on: if you reassign the value of a variable, TypeScript essentially gives up on its narrowing. 第二件事:如果您重新分配变量的值,TypeScript本质上放弃了它的范围缩小。 The compiler makes a considerable effort to understand the affect of control flow on variable types, but it's not perfect . 编译器付出了相当大的努力来理解控制流对变量类型的影响,但这并不完美 So, even though we understand that assigning AllowedValues.LOREM_IPSUM to value makes it an AllowedValues , the compiler gives up and assumes that it is its original annotated type, which is string . 因此,即使我们知道将AllowedValues.LOREM_IPSUM分配给value使其成为AllowedValues ,编译器AllowedValues 放弃并假定它是其原始的带注释类型,即string

The way to deal with this is to make a new variable which the compiler understands will never be anything but an AllowedValues . 处理此问题的方法是创建一个新变量,编译器将其理解为除AllowedValues任何AllowedValues The most straightforward way to do that is to make it a const variable, like this: 最简单的方法是使其成为const变量,如下所示:

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

In the above, the new variable allowedValue is inferred as an AllowedValues because it is set as either value if the type guard succeeds (at which point value is an AllowedValues ), or AllowedValues.LOREM_IPSUM if the type guard fails. 在上面的方法中,新变量allowedValue被推断为AllowedValues因为如果类型保护成功, AllowedValues其设置为value (此时valueAllowedValues ),如果类型保护失败, AllowedValues.LOREM_IPSUM其设置为AllowedValues.LOREM_IPSUM Either way, allowedValue is an AllowedValues . 无论哪种方式, allowedValue都是AllowedValues


So that would be my suggested change if you want to help the compiler understand things. 因此,如果您想帮助编译器理解事情,那将是我建议的更改。 Hope that helps. 希望能有所帮助。 Good luck! 祝好运!

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

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