【问题标题】:How to create a TypeScript @enumerable(false) decorator for a property如何为属性创建 TypeScript @enumerable(false) 装饰器
【发布时间】:2017-04-17 05:58:08
【问题描述】:

我想在 TypeScript 中创建一个装饰器,以便能够使类属性不可枚举。

我在这里找到了@enumerable 的示例: https://www.typescriptlang.org/docs/handbook/decorators.html#method-decorators 但这似乎只适用于方法,而不适用于属性:

https://www.typescriptlang.org/docs/handbook/decorators.html#property-decorators

注意  属性描述符不作为参数提供给 属性装饰器由于属性装饰器的初始化方式 打字稿。这是因为目前没有机制 在定义原型成员时描述实例属性, 并且无法观察或修改属性的初始化程序。作为 因此,属性装饰器只能用于观察一个属性 已为类声明了特定名称。

有没有办法为类属性创建 @enumerable 装饰器?

谢谢

【问题讨论】:

    标签: typescript properties decorator enumerable


    【解决方案1】:

    我最终得到了这个解决方案:

    /**
     * @enumerable decorator that sets the enumerable property of a class field to false.
     * @param value true|false
     */
    function enumerable(value: boolean) {
        return function (target: any, propertyKey: string) {
            let descriptor = Object.getOwnPropertyDescriptor(target, propertyKey) || {};
            if (descriptor.enumerable != value) {
                descriptor.enumerable = value;
                descriptor.writable= true;
                Object.defineProperty(target, propertyKey, descriptor)
            }
        };
    }
    

    用法:

    class User {
        id:string;
    
        @enumerable(false)
        name: string;
    }
    

    测试:

       var user = new User();
       user.id = 1;
       user.name = 'John Doe';
       for (key in user){ console.log(key, user[key]);}
    

    输出

    id 1
    

    不使用装饰器的相同测试

    id 1
    name John Doe
    

    【讨论】:

    • 当你使用Object.defineProperty时,它默认设置writable标志为false,所以你必须在这个装饰器中处理所有的prop元数据
    • 这不再起作用(使用 TypeScript 4.1.3),@JohnLock 下面的那个起作用了。
    • 只是对使用符号作为属性名称的其他人的说明,您可以使用return function (target: any, propertyKey: keyof any) {,这应该允许string | symbol | number
    【解决方案2】:

    此解决方案实际上不起作用,或者不适用于现代打字稿。但是,以下是:

    const enumerable: {
        (target: any, name: string): void;
        (target: any, name: string, desc: PropertyDescriptor): PropertyDescriptor;
    } = (target: any, name: string, desc?: any) => {
        if(desc) {
            desc.enumerable = true;
            return desc;
        }
        Object.defineProperty(target, name,  {
            set(value) {
                Object.defineProperty(this, name, {
                    value, enumerable: true, writable: true, configurable: true,
                });
            },
            enumerable: true,
            configurable: true,
        });
    };
    
    const nonenumerable: {
        (target: any, name: string): void;
        (target: any, name: string, desc: PropertyDescriptor): PropertyDescriptor;
    } = (target: any, name: string, desc?: any) => {
        if(desc) {
            desc.enumerable = false;
            return desc;
        }
        Object.defineProperty(target, name,  {
            set(value) {
                Object.defineProperty(this, name, {
                    value, writable: true, configurable: true,
                });
            },
            configurable: true,
        });
    };
    

    【讨论】:

    • 尝试了一堆解决方案,这是唯一对我有用的解决方案。
    • 只是对使用符号作为属性名称的其他人的说明,您可以使用name: keyof any 而不是name: string,这应该允许string | symbol | number
    猜你喜欢
    • 1970-01-01
    • 2019-07-29
    • 1970-01-01
    • 2020-06-20
    • 1970-01-01
    • 1970-01-01
    • 2021-05-17
    • 2011-03-15
    • 2018-07-20
    相关资源
    最近更新 更多