[英]is it possible to create dynamic properties to a class?
我将枚举包装在 class 中,因此我可以 map 其值在 TypeScript
enum Color {
RED = 0,
GREEN = 1,
BLUE = 2
}
const MapColor = new EnumMap(Color); // Wrapper
console.log(MapColor.map()) // [{ "key": "RED", "value": 0}, { "key": "GREEN","value": 1}, { "key": "BLUE", "value": 2}]
console.log(MapColor.entries()) // [["RED", 0], ["GREEN", 1], ["BLUE", 2]]
console.log(MapColor.keys()) // ["RED", "GREEN", "BLUE"]
console.log(MapColor.values()) // [0, 1, 2]
包装 Class
class EnumMap {
private _map = new Map<string, string | number>();
public enum: any;
constructor(enumeration: any) {
this.init(enumeration);
return this;
}
private init(enumeration: any) {
this._map = new Map<string, string | number>();
for (let key in enumeration) {
if (!isNaN(Number(key))) continue;
const val = enumeration[key] as string | number;
if (val !== undefined && val !== null) this._map.set(key, val);
}
this.enum = enumeration;
}
map = (): Object => Array.from(this._map.entries()).map((m) => ({ key: m[0], value: m[1] }));
entries = (): any[] => Array.from(this._map.entries());
keys = (): any[] => Array.from(this._map.keys());
values = (): any[] => Array.from(this._map.values());
}
我想直接访问一个枚举值,我想这样做
MapColor.RED // 0
MapColor.RED.toString() // 'RED'
是否可以为 class 创建动态属性? 如果可能的话,它会怎么做?
在旁边:
我忽略了MapColor.RED
为0
但MapColor.RED.toString()
评估为"RED"
的请求。 如果您希望MapColor.RED === Color.RED
为true
,那么MapColor.RED
是值为0
的number
(原始数据类型),您完全不可能将"RED"
作为其字符串值,因为(0).toString()
只是"0"
。 如果您希望MapColor.RED
成为一个Number
(包装器对象),您可以将其作为Object.assign(Number(0), {toString(){return "RED"})
来实现,但结果很糟糕。 它有点像0
( MapColor.RED + 5 === 5
),除非它不是,因为MapColor.RED === 0
是false
,并且someObject[MapColor.RED]
将访问someObject
的RED
属性,而不是0
属性。 因此,您要么不能这样做,要么可以但不应该这样做。 所以我假装它不存在。
回答:
您可以通过将enumeration
的属性直接复制到构造函数中的this
来实现这样的 class(我猜是init()
方法)。 您可以通过交集使用generics来描述此类 class 构造函数的类型。 你不能做的是让编译器验证实现是否符合描述。 因此,您需要在多个地方使用类型断言来告诉编译器您的 class 实例和 class 构造函数符合相关行为:
class _EnumMap<T extends Record<keyof T, string | number>> {
private _map = new Map<keyof T, T[keyof T]>();
public enum!: T;
constructor(enumeration: T) {
this.init(enumeration);
return this;
}
private init(enumeration: T) {
this._map = new Map<keyof T, T[keyof T]>();
for (let key in enumeration) {
if (!isNaN(Number(key))) continue;
const val = enumeration[key];
if (val !== undefined && val !== null) {
this._map.set(key, val);
(this as any)[key] = val; // set value here
}
}
this.enum = enumeration;
}
map = () => Array.from(this._map.entries())
.map((m) => ({ key: m[0], value: m[1] })) as
Array<{ [K in keyof T]: { key: K, value: T[K] } }[keyof T]>;
entries = () => Array.from(this._map.entries()) as
Array<{ [K in keyof T]: [K, T[K]] }[keyof T]>;
keys = () => Array.from(this._map.keys()) as Array<keyof T>;
values = () => Array.from(this._map.values()) as Array<T[keyof T]>;
}
我已将EnumMap
重命名为_EnumMap
并在最后恢复EnumMap
名称:
type EnumMap<T extends Record<keyof T, string | number>> = _EnumMap<T> & T;
const EnumMap = _EnumMap as
new <T extends Record<keyof T, string | number>>(enumeration: T) => EnumMap<T>;
重命名的EnumMap
在传递给它的enumeration
object 的类型T
中是通用的。 在init()
我写this[key] = val
,但编译器不知道this
应该有与 key 对应的key
,所以我将其断言this as any
以放松编译器警告。 我也更改了所有现有方法的 output 类型,以更正确地对应于您从中得到的内容...但您没有要求,所以保留any
和Object
(或者可能是object
) .
通过编写type EnumMap<T> = _EnumMap<T> & T
,我是说EnumMap<T>
既充当您的原始 class ,又充当T
。 因此,如果T
看起来有点像{RED: 0, GREEN: 1, BLUE: 2}
,那么EnumMap<T>
也将具有这些属性。 通过将const EnumMap = _EnumMap as new<T>(enumeration: T) => EnumMap<T>
,我是说原来的 class 构造函数已被复制到一个名为EnumMap
的值,并且可以被视为 class 构造函数对于新的EnumMap<T>
的实例。
让我们测试一下:
enum Color {
RED = 0,
GREEN = 1,
BLUE = 2
}
const MapColor = new EnumMap(Color); // Wrapper
console.log(MapColor.map()) // [{ "key": "RED", "value": 0},
// { "key": "GREEN","value": 1}, { "key": "BLUE", "value": 2}]
console.log(MapColor.entries()) // [["RED", 0], ["GREEN", 1], ["BLUE", 2]]
console.log(MapColor.keys()) // ["RED", "GREEN", "BLUE"]
console.log(MapColor.values()) // [0, 1, 2]
console.log(MapColor.RED) // 0
console.log(MapColor.GREEN) // 1
console.log(MapColor.BLUE) // 2
在我看来很好。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.