javascript - 是否可以为类创建动态属性?
问题描述
我将枚举包装在一个类中,以便可以在 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 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'
是否可以为类创建动态属性?如果可能的话,它会怎么做?
解决方案
在旁边:
我忽略了但评估为MapColor.RED
的请求。如果你想成为,那么就是值是 的 (原始数据类型),你完全不可能得到它的字符串值,因为 只是。如果你想成为一个(包装对象),你可以把它做为,但结果很糟糕。它有点像( ),除非它不这样做,因为它是,并且将访问 的属性,而不是0
MapColor.RED.toString()
"RED"
MapColor.RED === Color.RED
true
MapColor.RED
number
0
"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]
RED
someObject
0
财产。因此,您要么不能这样做,要么可以但不应该这样做。所以我假装它不存在。
回答:
您可以通过将 的属性直接复制到构造函数(或方法,我猜)内部来实现这样的类。您可以通过交集使用泛型来描述此类构造函数的类型。你不能做的是让编译器验证实现是否符合描述。因此,您需要在多个地方使用类型断言来告诉编译器您的类实例和类构造函数符合相关行为:enumeration
this
init()
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
类型中是通用的。在里面我写了,但是编译器不知道应该有对应的键,所以我断言放松编译器警告。我也更改了所有现有方法的输出类型,以更正确地对应于您从中得到的内容......但您没有要求这样做,所以如果必须,请保留和(或可能)。T
enumeration
init()
this[key] = val
this
key
this as any
any
Object
object
通过编写type EnumMap<T> = _EnumMap<T> & T
,我是说 anEnumMap<T>
既充当您的原始类,又充当T
. 因此,如果T
看起来有点像{RED: 0, GREEN: 1, BLUE: 2}
,那么EnumMap<T>
也将具有这些属性。通过写作const EnumMap = _EnumMap as new<T>(enumeration: T) => EnumMap<T>
,我是说原始类构造函数已被复制到一个名为 的值EnumMap
,并且可以被视为 new 实例的类构造函数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
对我来说看上去很好。
推荐阅读
- php - Postgres PHP查询多个值并按顺序在conlums html中打印结果
- angular - Angular LoggedIn 方法
- google-sheets - 使用同一列的计数和透视查询
- c++ - 使用类 c++ 显示 2 名员工之间输入最多的薪水
- typescript - 打字稿泛型,无需函数调用即可推断对象属性类型
- pvlib - pvlib:在给定 DNI 和 GHI 值的情况下,在 DHI 中填充空值的最准确方法
- pytorch - pytorch index_put_ 给出 RuntimeError: 'indices' 的导数未实现
- mysql - 使用 k8s StatefulSet 配置 MySQL 复制
- datetime - 在 Postman 中设置 DateStart 和 DateEnd 变量以表示“昨天”
- go - 具有私有依赖的 Vercel Golang 无服务器