是否可以编写一个通用枚举成员名称getter



我想写一个函数,它可以获得传递给它的枚举成员的名称

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版本是否支持该功能而按原样或降级发出;或
  • 纯粹基于类型系统(例如,类型注释、interfaces(,并且只是从发出的JavaScript中完全删除

enums有点奇怪,因为它们既没有被擦除,也没有按原样发射。在发出的JavaScript中,enum对象(例如CarsTrucks(只是一个普通的旧JavaScript对象将键映射到值。这些enum值(例如Cars.dodgeTrucks.gmc(只是数字或字符串。

您的CarsTrucks枚举像以下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在运行时的值只是数字0Trucks.ford在运行时也是如此。


因此,如果您询问是否可以实现getEnumMemberName(),使得getEnumMemberName(Cars.dodge)==="dodge"getEnumMemberName(Trucks.ford)==="ford"";,不幸的是,答案是。在运行时,Cars.dodgeTrucks.ford只是0,因此getEnumMemberName(0)必须根据其不可用的信息同时产生"dodge""ford"


如果您愿意编写getEnumMemberName(),使其接受两个参数,其中额外的一个是enum对象,那么可以编写此参数,因为缺少的枚举映射信息现在将可用。

由于CarsTrucks枚举是数字的,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;
}

到代码的游乐场链接

相关内容

  • 没有找到相关文章