【问题标题】:How to store meta information of properties in a class如何在类中存储属性的元信息
【发布时间】:2020-10-16 11:45:07
【问题描述】:

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

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

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"}

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

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

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

【问题讨论】:

    标签: typescript properties metadata


    【解决方案1】:

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

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-12
      • 2021-08-17
      • 1970-01-01
      • 1970-01-01
      • 2014-05-27
      • 2013-10-30
      • 2016-01-18
      相关资源
      最近更新 更多