为啥 enumerable: false 不会级联到 TypeScript 中的继承类?

Posted

技术标签:

【中文标题】为啥 enumerable: false 不会级联到 TypeScript 中的继承类?【英文标题】:Why does enumerable: false not cascade to inherited classes in TypeScript?为什么 enumerable: false 不会级联到 TypeScript 中的继承类? 【发布时间】:2018-12-14 06:56:12 【问题描述】:

如果我使用 TypeScript 和下面的方法将属性标记为 @enumerable(false),则扩展此可枚举标记为 false 的父类的子类将具有该属性,但它将可从 this answer 获取。

export 

declare global 
    function enumerable(value: boolean): any;


const _global = (global /* node */ || window /* browser */) as any;

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

这是我的层次结构的样子:

class BaseObject 
    @enumerable(false)
    public _metadata: any = 
        id: 'number',
        name: 'string'
    ;


class ContainerObject extends BaseObject 
    // ...


class CanvasObject extends BaseObject 
    // ...

这是运行时描述符的值:

var canvas = new CanvasObject();
console.log('Metadata Descriptor: ');
console.log(Object.getOwnPropertyDescriptor(canvas, '_metadata'));
Metadata Descriptor:
 value: 
    beanId: 'number',
     name: 'string' ,
  writable: true,
  enumerable: true,
  configurable: true 

如何确保该属性在父类和所有后续继承类中为enumerable: false

【问题讨论】:

你必须自己做。 javascript 中的继承不涉及继承这些标志。 每个原型对象都是它自己独特的对象,并且那些对象属性API与原型没有任何特殊关系;它们适用于所有对象。 使用原型链,您无法使用getOwnPropertyDescriptor 使用子作为参数来获取属性描述符,因为该属性属于原型,而不是子对象。我错过了什么吗? 我可以阻止我的子类完全从父类继承 _metadata 对象吗? 对不起@J.Pichardo,我在代码中留下了一个错字。我正在获取canvas 的属性描述符。 【参考方案1】:

这是由于在类声明中对类原型应用了装饰器。由于_metadata 是实例属性(它被脱糖为constructor() this._metadata = ... ),enumerable 装饰器不会影响它。

这是一个enumerable 装饰器的示例,它可以应用于原型(通常是方法)和实例属性:

function enumerable(value: boolean) 
  return (target: any, prop: string, descriptor?: PropertyDescriptor) => 
    if (descriptor) 
      // prototype property
      descriptor.enumerable = value;
     else 
      // instance property
      let propSymbol = Symbol(prop);

      Object.defineProperty(target, prop, 
        configurable: true,
        enumerable: value,
        get()  return this[propSymbol] ,
        set(value)  this[propSymbol] = value 
      );
    
  ;

请注意,为了处理 _metadata = ... 属性初始化器,描述符应包含 set 访问器以捕获属性分配。

【讨论】:

好吧,我对此进行了测试,我认为它现在正在创建属性并正确地使其不可枚举,但它没有在对象中设置 _metadata 的值并返回 undefined对于dna._metadata 它应该按预期工作,stackblitz.com/edit/typescript-nam2ew。您可以看到 _metadata 存在并且在 Chrome 控制台输出(浅色)中不可枚举。 如何防止 TypeScript 将元数据分配脱糖到构造函数中?我在我的编译器选项中设置了target: "esnext",但它总是脱糖到构造函数中,然后分配似乎失败了。 我不知道 esnext 目标所涵盖的确切列表是什么,但我不希望类字段保持原样,因为它们本身不受支持。 “语法糖”意味着它在功能上与脱糖对应物相同。不管是什么问题,都不应该是由它引起的。在我发布的示例中,类字段显然在编译时与构造函数代码脱糖。 我将 _metadata 重命名为 metadata 并将我的目标从 esnext 更改为 es2017 并且它正在工作!非常感谢,我需要在本周末之前完成这项工作。

以上是关于为啥 enumerable: false 不会级联到 TypeScript 中的继承类?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Enumerator 包含 Enumerable

为啥 Enumerable 中的方法返回 Enumerator?

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

为啥重复 Enumerable 到 Observable 转换块

为啥 Enumerable 在 Ruby 中没有长度属性?

js对象中什么是可枚举性(enumerable)?