我想写一个函数,它可以获得传递给它的枚举成员的名称
enum Cars {
dodge,
ford,
toyota
}
enum Trucks {
ford,
nissan,
gmc
}
class Foo() {
truckType : Trucks;
}
const getEnumMemberName = function(enumMember : any) : string {
//implementation?
}
const main = function() {
let f = new Foo();
foo.truckType = Trucks.ford;
console.log(`Trucktype is ${getEnumMemberName(foo.truckType}`);
}
main();
//Should log "Trucktype is ford" to the console
我认为,如果不将枚举类型本身提供给函数,这可能是不可能的,因为尽管foo.truckType类型为Trucks,但运行时的所有字段似乎都是一个没有可用类型信息的数字。
我知道a(我可以将枚举定义为字符串值,而不是默认数字,而且我还知道,如果我知道使用let name = Trucks[foo.trucktype]
的枚举名称,我可以获得成员的名称。我的问题是,您是否可以从类型为枚举(如truckType : Trucks
(的变量推断枚举类型,还是只是转换为数字,类型信息不可用?
TypeScript中的大多数功能是:
- 来自某些版本的JavaScript(例如,
class
是ES2015+(,并根据目标JS版本是否支持该功能而按原样或降级发出;或 - 纯粹基于类型系统(例如,类型注释、
interface
s(,并且只是从发出的JavaScript中完全删除
但enum
s有点奇怪,因为它们既没有被擦除,也没有按原样发射。在发出的JavaScript中,enum
对象(例如Cars
或Trucks
(只是一个普通的旧JavaScript对象将键映射到值。这些enum
值(例如Cars.dodge
或Trucks.gmc
(只是数字或字符串。
您的Cars
和Trucks
枚举像以下JavaScript:一样发出
var Cars;
(function (Cars) {
Cars[Cars["dodge"] = 0] = "dodge";
Cars[Cars["ford"] = 1] = "ford";
Cars[Cars["toyota"] = 2] = "toyota";
})(Cars || (Cars = {}));
var Trucks;
(function (Trucks) {
Trucks[Trucks["ford"] = 0] = "ford";
Trucks[Trucks["nissan"] = 1] = "nissan";
Trucks[Trucks["gmc"] = 2] = "gmc";
})(Trucks || (Trucks = {}));
这有点复杂,但您可以验证Cars.dodge
在运行时的值只是数字0
,Trucks.ford
在运行时也是如此。
因此,如果您询问是否可以实现getEnumMemberName()
,使得getEnumMemberName(Cars.dodge)==="dodge"
和getEnumMemberName(Trucks.ford)==="ford"
";,不幸的是,答案是否。在运行时,Cars.dodge
和Trucks.ford
只是0
,因此getEnumMemberName(0)
必须根据其不可用的信息同时产生"dodge"
和"ford"
如果您愿意编写getEnumMemberName()
,使其接受两个参数,其中额外的一个是enum对象,那么可以编写此参数,因为缺少的枚举映射信息现在将可用。
由于Cars
和Trucks
枚举是数字的,TypeScript已经为您提供了反向映射:例如,如果是Cars.dodge === 0
,则是Cars[0] === "dodge"
。(这就是上面的"复杂"代码所做的。(
如果您只需要支持数字枚举,那么getEnumMemberName()
可以通过简单的对象索引实现:
const getEnumMemberName = function (enumObj: Record<number, string>, enumMember: number): string {
return enumObj[enumMember];
}
数值枚举对象被认为可以分配给Record<number, string>
:这意味着number
键应该产生string
值,这是由于反向映射。然后以下代码按预期工作:
let foo = new Foo();
foo.truckType = Trucks.ford;
console.log(`Trucktype is ${getEnumMemberName(Trucks, foo.truckType)}`);
// Trucktype is ford
如果您想编写getEnumMemberName()
并使其适用于任意枚举(不仅是number
,还有string
枚举(,并且您没有多个枚举键具有相同值的情况,您可以搜索枚举对象,而不是依赖反向映射:
const getEnumMemberName = function <T>(enumObj: T, enumMember: T[keyof T]): keyof T {
const key = (Object.keys(enumObj) as Array<keyof T>).find(k => enumObj[k] === enumMember);
if (typeof key === "undefined") throw new Error("Not an enum member");
return key;
}
到代码的游乐场链接