Как сохранить имя класса, используя миксин со статическими атрибутами в машинописи - PullRequest
0 голосов
/ 27 сентября 2019

Я не понимаю проблемы, возникшей при разработке миксина, используемого в качестве декоратора, если в код микса включен статический атрибут, имя моего класса изменяется в процессе.

Интерфейс определен в одном файле

export interface IElement {
  register(param: any): void;
};

В другом файле мой миксин я буду использовать в качестве декоратора:

export type Constructor<T = {}> = new (...args: any[]) => T;

export function Composite<T extends Constructor>(target: T) {
  return class extends target implements IElement {
    public static asGlobal: boolean; // <- If asGlobal is initialized, the class name is changed
    public static declareGlobal() {
      this.asGlobal = true;
      return this;
    }

    constructor(...args: any[]) {
      super(...args);
    }

    public register(param: any) {
      // Some stuff
    }

    // ...

  };
};

В другом файле я хочу 't использовать мой Mixin следующим образом:

@Composite
class MyCompositeA {
 // All my class stuff
};

MyCompositeA.declareGlobal(); // <- error TS2339: Property 'declareGlobal' does not exist on type 'typeof MyComposite'.


const testElem = new MyCompositeA();
console.log(testElem.constructor.name); // <- return '_a' if the boolean is initialized and MyCompositeA in the other case 

Playground

Как я вижу в сгенерированном Javascript, когда добавляется значение инициализации, создается временный классв коде и возвращается как новый тип.

У меня два вопроса:

  • Есть ли решение сохранить исходное имя класса, я не хочу использовать внедрение зависимостей.Если я создаю второй класс с декоратором, его имя совпадает (сгенерировано _a).
  • Можно ли избежать ошибки DeclareGlobal unknown?

ОБНОВЛЕНИЕ:

В ответ на комментарий Алуана Хаддада, я обновил игровую площадку ( PlayGround ), если я создаю два класса, используя эту функцию с инициализированным логическим значением,Поле constructor.name одинаково для любого экземпляра, созданного двумя разными классами.

Я получаю следующее дерево наследования с Node (небольшая разница с игровой площадкой) с логической инициализацией:

_a <- MyCompositeA <- Object
_a <- MyCompositeB <- Object

И без:

MyCompositeA <- Object
MyCompositeB <- Object

Не знаюне знаю, нормальная ли это ситуация или нет.

ОБНОВЛЕНИЕ2:

Я полностью переработал свою реализацию, изменил функцию класса и могу сохранитьимя моего класса, как и требовалось изначально:

interface IElement {
  register(param: any): void;
}

class CElement implements IElement {
  public static asGlobal: boolean = false;
  public static declareGlobal() {
    this.asGlobal = true;
    return this;
  }

  constructor(public pEl: string) {}

  register(param: any) {
    console.log('register', param, this.pEl);
  }
}

type Constructor<T = {}> = new (...args: any[]) => T;

function Composite<T extends Constructor>(Target: T) {
  let container = {
    [Target.name]: class extends CElement {  // Little hack here to force the name of the class
      constructor () {
          super('Try');
          Target.constructor.apply(this, []);
      }
    }
  };

  let result = container[Target.name];
  Object.getOwnPropertyNames(Target.prototype).forEach(name => {
    Object.defineProperty(result.prototype, name, {value: Target.prototype[name]});
  });
  return container[Target.name];
}

const MyCompositeA = Composite(
class MyCompositeA {

  f() {
    console.log("Inheritance f: OK");
  }
});

const MyCompositeB = Composite(
class MyCompositeB {
  g() {
    console.log("Inheritance g: OK");
  }
});

Единственная оставшаяся ошибка - это то, что я хотел добавить «реализует цель» в моем определении класса, но кажется, что это невозможно (ошибка: «Цель» относитсяк значению, но используется здесь как тип.) Playground

Ошибка, которую я не понимаю, потому что мы можем расширить Target, но не реализовать ее ???Извините за несколько вопросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...