在 TypeScript Mixin 之后重写抽象 getter
我有一个应用程序,使用了一些带有 Mixin 模式的通用类,并且正在尝试实现一个属性 getter,这个 getter 对于 90% 的 Mixin 用户来说是一样的,但并非完全相同…
我惊讶地发现:
- 可以定义抽象方法,在混入中实现它们,并在子类中重写它们
- 在 mixin 中定义新的属性 getter 并在子类中重写它们是可以的
- 但是,尝试在 mixin 中定义抽象属性的 getter,实现 它们,并在子类中重写它们——会引发错误吗?
并且当我尝试在子类中重写混入中定义的属性获取器时,发现了一个意想不到的问题。
下面是一个小的代码片段,试图演示所有三种行为——有人能帮我理解为什么第3点是一个错误,以及是否有好的方法来修复它吗?我希望保持 TextThing 的任何子类被强制实现抽象属性的安全性……
/**
* Basic interface objects should implement
*/
export interface ITextThing<T> {
dataSource: T;
html(): string;
get text(): string;
}
/**
* Abstract base class with partial implementation
*/
export abstract class TextThing<T> implements ITextThing<T> {
dataSource: T;
constructor(data: T) {
this.dataSource = data;
}
abstract html(): string;
abstract get text(): string;
}
type AbstractOrConcreteConstructor<T> = (new (...args: any[]) => T) | (abstract new (...args: any[]) => T);
/**
* A mixin with extra functionality
*/
export function WithCounter<T extends AbstractOrConcreteConstructor<{}>>(SuperClass: T) {
return class extends SuperClass {
_counter: number;
constructor(...args: any[]) {
super(...args);
this._counter = 0;
}
get count(): number {
return this._counter;
}
get text(): string {
return `[${this._counter}]`;
}
};
}
/**
* The problem class: Using the mixin...
*/
export class TextWithCounter<TData> extends WithCounter(TextThing)<TData> {
constructor(data: TData, initialCount = 0) {
super(data);
this._counter = initialCount;
}
// Overriding a getter defined in the mixin seems fine...
override get count(): number {
return this._counter + 1;
}
// Overriding a base class abstract function implemented in mixin seems fine...
html(): string {
return `<p><strong>${this.count}: </strong>${this.dataSource}</p>`;
}
// But base class abstract getter implemented in the mixin throws an error?
// > 'text' is defined as a property in class 'WithCounter<typeof TextThing>.(Anonymous class)
// & TextThing<TData>', but is overridden here in 'TextWithCounter<TData>' as an
// accessor.ts(2611)
override get text(): string {
return `[${this.count}]: ${this.dataSource}`;
}
}
这个项目目前使用的是 TypeScript v4.5.4,但如果升级可能会有帮助?我不太确定这是一个错误/限制,还是我们代码的问题……
答案#1
我认为这是由这个错误引起的。我认为 getter 通常被视为只读属性,这在像这样继承时会成为一个问题。然而,方法可以正常工作,所以解决这个问题的一种方法可能是将 get text() 的声明和定义替换为 getText(),然后在抽象类中添加 get text() 的具体实现,该实现再调用 getText()。所以 TextThing 变成:
export abstract class TextThing<T> implements ITextThing<T> {
dataSource: T;
constructor(data: T) {
this.dataSource = data;
}
abstract html(): string;
abstract getText(): string;
get text(): string {
return this.getText();
}
}
