如何在类中存储属性的元信息 [英] How to store meta information of properties in a class

查看:62
本文介绍了如何在类中存储属性的元信息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将元数据与类中的属性相关联,特别是属性名称的缩写.

I want to associate metadata to properties in classes, specifically abbreviations of property names.

使用注释:@shortName(abbreviated),您可以标记每个属性:

With annotations: @shortName(abbreviated) you can tag each property:

function shortName(shortName: string){
    return function (target: Object, realName: string){
        // Where to store the relation realName <-> shortName ??
    }
}
class Record{
    @shortName("ts") typeOfStorage: string;
}
class Client extends Record{
    @shortName("df") descriptiveField: string;
}
function mapNames(obj: any){  // Return object with shortened names
    let ret = {};
    for(let prop in obj){
        //Here retrieve the short name and add to ret
    }
    return ret;
}

let client = new Client();               // supposing: { typeOfStorage: "f", descriptiveField: "blah"}
let clientShortened = mapNames(client);  // expected:  {ts: "f", df: "blah"}

问题是我在哪里以及如何存储这些关系,以便在派生类的实例中可以检索它们?

The question is where and how do I store these relations so they are retrievable in instances of derived classes?

最初,我创建了一个全局映射,前缀为 target.constructor.name(给出了类的名称).但是在继承的类中,constructor.name 是继承的(所以在示例 client 中,我会忘记 typeOfStorage

Initially, I was creating a global map prefixing with target.constructor.name (that gives the name of the class). But in an inherited class the constructor.name is the inherited one (so in the example client I'd lose track of typeOfStorage

(这样做的用途是为了节省空间,在nonSql DB中存储对象-firestore-存储每个对象-记录的每个属性名称)

(The use of this is to save space storing objects in nonSql DB -firestore- that store each property name of each object-record)

推荐答案

我可能会在类的原型上存储一张地图.当解析对象的属性时,您可以通过递归调用 Object.getPrototypeOf 来获取原型链,从对象实例开始.您必须合并原型链中的所有地图(或仅在每个地图中单独查找属性).

I would probably store a map on the prototype of the class. When resolving properties for an object you then can acquire the prototype chain by recursively calling Object.getPrototypeOf, starting with the object instance. You will have to merge all the maps in the prototype chain (or just look up the property in every map individually).

function shortName(shortName: string)
{
    return function (target: Object, realName: string)
    {
        const t = target as { _propMap?: Map<string, string> };

        if (t._propMap == null)
        {
            // This is probably overkill, because people usually iterate
            // properties on the instances, not the prototype.
            // Setting enumerable: false hides the property.
            Object.defineProperty(t, '_propMap', {
                enumerable: false,
                writable: true,
            });

            t._propMap = new Map<string, string>();
        }

        t._propMap.set(realName, shortName);
    }
}

function getMap(obj: any)
{
    // Might want to get the chain first, then iterate in reverse
    // so child properties override parent properties
    const map = new Map<string, string>();
    while (true)
    {
        obj = Object.getPrototypeOf(obj);
        if (obj == Object.prototype)
            return map;

        if (obj._propMap)
        {
            let subMap = obj._propMap as Map<string, string>;
            subMap.forEach((v, k) => map.set(k, v));
        }
    }
}

function mapNames(obj: any)
{
    const map = getMap(obj);

    const ret: any = {};
    for (let prop in obj)
    {
        const name = map.get(prop) ?? prop;
        ret[name] = obj[prop];
    }

    return ret;
}

这篇关于如何在类中存储属性的元信息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆