如何为属性创建 TypeScript @enumerable(false) 装饰器

Posted

技术标签:

【中文标题】如何为属性创建 TypeScript @enumerable(false) 装饰器【英文标题】:How to create a TypeScript @enumerable(false) decorator for a property 【发布时间】: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 装饰器?

谢谢

【问题讨论】:

【参考方案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

以上是关于如何为属性创建 TypeScript @enumerable(false) 装饰器的主要内容,如果未能解决你的问题,请参考以下文章

如何为 React Native 嵌套组件创建 Typescript 定义

如何为无状态 React 组件创建 TypeScript 类型定义?

如何为 TypeScript 配置 Sublime 构建系统

TypeScript 如何为泛型函数创建泛型类型别名?

如何为 TypeScript React 应用程序设置键/值默认状态

如何为 useReducer 键入 state 和 dispatch - typescript 和 react