繁体   English   中英

获取字符串枚举值的类型

[英]getting a type for the values of a string enum

我有一个字符串枚举,看起来像:

export enum FMEvents {
  RECORD_ADDED = "@firemodel/RECORD_ADDED",
  RECORD_CHANGED = "@firemodel/RECORD_CHANGED",
  RECORD_MOVED = "@firemodel/RECORD_MOVED",
  RECORD_REMOVED = "@firemodel/RECORD_REMOVED",
}

我希望能够将函数的输入限制为枚举的字符串值(例如,“@firemodel/RECORD_ADDED”等)。

我想我也许可以对方法签名执行以下操作:

public doSomething(event: keyof FMEvents) { ... }

但是输入都是错误的(我认为它给了我枚举对象的键,不确定但肯定是错误的)。

然后我尝试了:

public doSomething(event: FMEvents) { ... }

这允许我使用FMEvents.RECORD_CHANGED调用doSomething()但它不允许我使用doSomething("@firemodel/RECORD_CHANGED")的解析键调用它。

我正在寻找的是一种将其约束为定义为 Enum 中的值的字符串的方法,而不是其他任何东西。 有了这个,我希望上面的两种调用方法都能通过类型检查。

TypeScript 4.1 引入了模板文字类型,其中包括将枚举转换为其字符串表示形式。 因此,您的目标可以简单地实现为:

function doSomething(event: `${FMEvents}`) { }

doSomething("@firemodel/RECORD_CHANGED"); // okay
doSomething(FMEvents.RECORD_MOVED); // still okay

Playground 链接到代码


TS4.1 之前的答案:

TypeScript 并不能轻松地将枚举值类型扩展到它们派生的字符串或数字文字。 (有一个复杂性阻止使用交集来帮助解决这个问题)您可以使用条件类型非常接近您想要的:

type Extractable<T, U> = T extends U ? any : never
type NotString<T> = string extends T ? never : any
function promoteStringToFMEvents<K 
  extends string & NotString<K> & Extractable<FMEvents, K>>(
  k: K
): Extract<FMEvents, K> {
  return k;
}

const fmAdded = promoteStringToFMEvents("@firemodel/RECORD_ADDED"); // FMEvents.RECORD_ADDED
const fmOops = promoteStringToFMEvents("@firemodel/RECORD_ADDLED"); // error

在上面的代码中, Extractable<T, U>返回any如果T或其任何成分可分配给U ,否则never 并且NotString<T>返回any T不是string或更宽的,否则never 通过将promoteStringToFMEvents() K限制为string & NotString<K> & Extractable<FMEvents, K> ,我们说类型参数K必须是某个元素(或元素的联合)的某个字符串文字(或字符串文字的并集) ) 的FMEvents可以分配给。

因此, promoteStringToFMEvents()函数将接受您期望的字符串文字(或字符串文字的并集)。 该函数还通过将输入值分配给Extract<FMEvents, K>来仅返回FMEvents的关联元素,这仅提取与K匹配的那些FMEvents片段。

因此,您可以编写doSomething()方法,使其在上述K类型中是通用的,并且在该方法的实现中,您可以(如果需要)通过将字符串分配给类型的变量来将其提升为枚举Extract<FMEvents, K>

使用doSomething()显式实现进行编辑:

class Blomp {
  public doSomething<K
    extends string & NotString<K> & Extractable<FMEvents, K>>(k: K) {
    // k is of some subtype of "@firemodel/RECORD_ADDED" | 
    // "@firemodel/RECORD_CHANGED" | "@firemodel/RECORD_MOVED" |
    // "@firemodel/RECORD_REMOVED"

    // if you need to interpret k as a subtype of FMEvents, you can:
    const kAsFMEvent: Extract<FMEvents, K> = k;

    // or even wider as just FMEvents
    const fmEvent: FMEvents = kAsFMEvent;

    // do what you want here
  }
}

希望有帮助。 祝你好运!

模板文字运算符的帮助下,枚举的值列表可以推断为一种类型:

export enum FMEvents {
  RECORD_ADDED = "@firemodel/RECORD_ADDED",
  RECORD_CHANGED = "@firemodel/RECORD_CHANGED",
  RECORD_MOVED = "@firemodel/RECORD_MOVED",
  RECORD_REMOVED = "@firemodel/RECORD_REMOVED",
}

type FMEventsValue = `${FMEvents}`
// => type FMEventsValue = "@firemodel/RECORD_ADDED" | "@firemodel/RECORD_CHANGED" | ...

const event: FMEventsValue = "@firemodel/RECORD_ADDED"
// => ✅ OK

const event: FMEventsValue = "NoT_iN_ThE_eNuM"
// => 🚨 KO

参考文章: 动态获取枚举的值(免责声明:作者在这里)

暂无
暂无

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

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