赞
enum Response {
@Descriptor("this is No")
No = 0,
@Descriptor("this is Yes")
Yes = 1,
}
如何在TypeScript中的枚举上使用装饰器,我尝试了这段代码,但是没有用
export function Description(description:string){
return Reflect.metadata(descriptionMetadataKey, description);
}
答案 0 :(得分:6)
简短的答案是,您不能(截至撰写本文时)。不过,还有其他选择。
如果您只想在枚举文字中添加说明,则可以使用文档注释。
enum Response {
/**
* this is No
*/
No = 0,
/**
* this is Yes
*/
Yes = 1,
}
虽然描述在运行时不可用,但它们会显示在编辑器自动完成中:
如果您 really , really 在运行时需要文字修饰的信息,则可以改用类。由于装饰器可以应用于类属性,因此您可以编写一个类,装饰其属性,然后使用该类的实例作为“枚举”。
function Descriptor(description: string) {
return (target: any, propertyName: string) => {
// process metadata ...
};
}
class ResponsesEnum {
@Descriptor("this is No")
readonly Yes = 1;
@Descriptor("this is No")
readonly No = 2;
}
const Responses = new ResponsesEnum();
here试试。
答案 1 :(得分:1)
不能。 can在TypeScript中使用修饰符的位置:
类装饰器
@sealed
class Greeter {}
方法装饰器
class Greeter {
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
访问装饰器
class Point {
private _x: number;
@configurable(false)
get x() { return this._x; }
}
属性装饰器
class Greeter {
@format("Hello, %s")
greeting: string;
}
参数修饰符
class Greeter {
greet(@required name: string) {
return "Hello " + name + ", " + this.greeting;
}
}
答案 2 :(得分:1)
另一种方法是将枚举值包装在类内部。然后,我们可以将装饰器应用于包装器类。这与this answer的“枚举类”替代方法不同,因为它保留了本机枚举。
优点是显而易见的。 G。更好的智能感知,类型安全性以及与期望本机枚举的API的兼容性。
一个缺点是用于声明和使用枚举的样板代码更多(例如,您必须编写new Response(value)
来初始化包装的枚举)。
枚举声明:
enum ResponseEnum {
No = 0,
Yes = 1,
}
@EnumDescriptor( ResponseEnum, {
No = "this is No",
Yes = "this is Yes",
// Instead of strings, one could assign arbitrary metadata:
// Yes = { answer: "this is Yes", more: 42 }
})
class Response {
constructor( public value: ResponseEnum = ResponseEnum.No ){}
}
上面的代码是 typesafe ,这是通过装饰器功能的键入而实现的(请参见下文)。如果我们错过了描述符中的枚举键,或者传递给@EnumDescriptor
的本机枚举类型与包装类使用的枚举键之间不匹配,则TS编译器将引发错误。
实例化枚举并获取元数据:
let r = new Response( ResponseEnum.Yes );
console.log("---VALUE---");
console.log( r );
console.log( +r ); // conversion to primitive, same as r.valueof()
console.log( r.valueOf() );
console.log( r.toString() );
console.log( JSON.stringify( r ) );
console.log("---METADATA---");
// Get metadata from variable
console.log( Reflect.getMetadata( EnumValuesMetadataKey, Object.getPrototypeOf( r ) ) );
console.log( Reflect.getMetadata( EnumDescriptorMetadataKey, Object.getPrototypeOf( r ) ) );
// Get metadata from the wrapper class:
console.log( Reflect.getMetadata( EnumValuesMetadataKey, Response.prototype ) );
console.log( Reflect.getMetadata( EnumDescriptorMetadataKey, Response.prototype ) );
控制台输出:
---VALUE---
Response {value: 1}
1
1
1
1
---METADATA---
{0: "No", 1: "Yes", No: 0, Yes: 1}
{No: "this is No", Yes: "this is Yes"}
{0: "No", 1: "Yes", No: 0, Yes: 1}
{No: "this is No", Yes: "this is Yes"}
修饰器功能(库代码)的实现:
尽管OP最初没有要求,但装饰器还通过EnumValuesMetadataKey
(有关键值的映射)存储有关原始枚举类型的元数据。我们已经有了这些信息,对于像对象编辑器这样的用例来说,这很重要,我们想在运行时知道哪些枚举键可用于给定的枚举成员。
此外,Object.prototype
的标准方法也被覆盖以“解包”本地枚举值,即转换为原始值(.valueOf()
),字符串(.toString()
)和JSON( .toJSON()
)。这类似于Number
这样的内置包装器类。
export interface IEnumWrapper< EnumT > {
value: EnumT;
}
type EnumWrapperCtor< EnumT > = new( value: EnumT ) => IEnumWrapper< EnumT >;
export const EnumValuesMetadataKey = Symbol("EnumValuesMetadataKey");
export const EnumDescriptorMetadataKey = Symbol("EnumDescriptorMetadataKey");
export function EnumDescriptor< EnumT, KeysT extends string >(
enumValues: { [ key in KeysT ]: EnumT },
descriptor: { [ key in KeysT ]: any })
{
return function( target: EnumWrapperCtor< EnumT > ) {
// Assign metadata to prototype of wrapper class
Reflect.defineMetadata( EnumValuesMetadataKey, enumValues, target.prototype );
Reflect.defineMetadata( EnumDescriptorMetadataKey, descriptor, target.prototype);
// Override standard methods to "unwrap" the enum value
target.prototype.valueOf = function() { return this.value };
target.prototype.toJSON = function() { return this.value; }
target.prototype.toString = function() { return this.value.toString() };
}
}
答案 3 :(得分:0)
装饰器对枚举无效。恐怕您不能以这种方式在枚举上使用装饰器。