Я не понимаю проблемы, возникшей при разработке миксина, используемого в качестве декоратора, если в код микса включен статический атрибут, имя моего класса изменяется в процессе.
Интерфейс определен в одном файле
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, но не реализовать ее ???Извините за несколько вопросов.