Почему enumerable: false не каскадируется к унаследованным классам в TypeScript? - PullRequest
0 голосов
/ 05 июля 2018

Если я отмечу свойство как @enumerable(false) с использованием TypeScript и описанного ниже метода, дочерние классы, расширяющие родительский класс, для которого это перечисляемое значение помечено как ложное, будут иметь свойство, но оно будет перечислимо, принимая этого ответа .

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 в родительском классе и всех последующих унаследованных классах?

1 Ответ

0 голосов
/ 05 июля 2018

Это связано с тем, что декоратор применяется к прототипу класса при объявлении класса. Так как _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 средство доступа для перехвата присваивания свойства.

...