问题描述
我有一个字符串枚举,看起来像:
I have a string enumeration that looks like:
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"等).
I'd like to be able to be able to constrain input into a function to the string values of enumeration (e.g., "@firemodel/RECORD_ADDED", etc.).
我想我也许可以对方法签名执行以下操作:
I thought I could maybe just do the following for the method signture:
public doSomething(event: keyof FMEvents) { ... }
但是输入都是错误的(我认为它给了我枚举对象的键,不确定但肯定是错误的).
but the typing for that is all wrong (I think it's giving me the keys of the enum object, not sure but definitely wrong).
然后我尝试了:
public doSomething(event: FMEvents) { ... }
这允许我用 FMEvents.RECORD_CHANGED
调用 doSomething()
但它不允许我用 doSomething("@firemodel/RECORD_CHANGED")
.
This allows me to call doSomething()
with FMEvents.RECORD_CHANGED
but it does not allow me to call it with the resolved key of doSomething("@firemodel/RECORD_CHANGED")
.
我正在寻找的是一种将其约束为定义为枚举中的值的字符串的方法,而不是其他任何东西.有了这个,我希望上面的两个调用方法都能通过类型检查.
What I'm looking for is a way to constraint it to the string defined as values in the Enum and nothing else. With this I'm hoping both calling methods above will pass the type checking.
推荐答案
TypeScript 4.1 引入 模板文字类型,其中包括将枚举转换为其字符串表示形式.因此,您的目标可以简单地实现为:
TypeScript 4.1 introduced template literal types which, among other things, will convert enums to their string representations. So your goal can be accomplished simply as:
function doSomething(event: `${FMEvents}`) { }
doSomething("@firemodel/RECORD_CHANGED"); // okay
doSomething(FMEvents.RECORD_MOVED); // still okay
TS4.1 之前的答案:
Pre TS4.1 answer:
TypeScript 不能轻松地将枚举值类型扩展到它们派生的字符串或数字文字.(有一个复杂性阻止使用交叉来帮助解决这个问题)你可以得到公平的使用 条件类型一个>:
TypeScript doesn't make it easy to widen enum value types to the string or numeric literals from which they derive. (There is a complication that prevents using intersections to help with this) You can get fairly close to what you want using conditional types:
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
在上面的代码中,如果 T
或其任何组成部分可分配给 ,
和 Extractable
返回 any
Unever
否则.并且 NotString
返回 any
是 T
不是 string
或更宽,并且 never
否则.通过将 promoteStringToFMEvents()
中的 K
限制为 string &NotString<K>&Extractable<FMEvents, K>
,我们说类型参数 K
必须是某个字符串文字(或字符串文字的并集),FMEvents
可以分配给.
In the above code, Extractable<T, U>
returns any
if T
or any of its constituents is assignable to U
, and never
otherwise. And NotString<T>
returns any
is T
isn't string
or wider, and never
otherwise. By constraining K
in promoteStringToFMEvents()
to string & NotString<K> & Extractable<FMEvents, K>
, we are saying that the type parameter K
must be some string literal (or union of string literals) that some element (or union of elements) of FMEvents
can be assigned to.
因此函数 promoteStringToFMEvents()
将接受您期望的字符串文字(或字符串文字的联合).该函数也只是通过将输入值分配给 Extract
来返回 FMEvents
的关联元素,它只提取那些 FMEvents
code> 匹配 K
.
So the function promoteStringToFMEvents()
will accept the string literals (or unions of string literals) you expect. The function also just returns the associated element of FMEvents
by assigning the input value to Extract<FMEvents, K>
, which pulls out just those pieces of FMEvents
which match K
.
因此您可以编写您的 doSomething()
方法,使其在上述 K
类型中是通用的,并且在该方法的实现中您可以(如果您需要)通过将字符串分配给 Extract
类型的变量来将字符串提升为枚举.
So you can write your doSomething()
method such that it is generic in the type of K
above, and in the implementation of the method you can (if you need to) promote the string to an enum by assigning it to a variable of type Extract<FMEvents, K>
.
使用 doSomething()
的显式实现进行
EDIT with explicit implementation of 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
}
}
希望有所帮助.祝你好运!
Hope that helps. Good luck!
这篇关于获取字符串枚举值的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!