angular - Finns det ett sätt i TypeScript att tvinga en klass att implementera/överskriva en statisk variabel?
Finns det ett sätt i TypeScript att tvinga en klass att implementera/åsidosätta en statisk variabel?
Användningsfall: Jag vill att användarna ska kunna välja en komponent från en lista med komponenter. Jag kommer sedan att visa användaren en förhandsgranskning av den komponent de valde. Jag vill att själva komponentklassen ska ha en widgetName statisk egenskap så att jag kan använda denna statiska egenskap i listningen av komponenter.
Vad jag har försökt hittills: Jag skapade en abstrakt klass, som varje komponent i listan kommer att utöka
export abstract class WidgetComponent {
static widgetName: string;
}
@Component({
selector: 'app-widget-one',
templateUrl: './widget-one.component.html',
styleUrls: ['./widget-one.component.scss'],
})
export class WidgetOneComponent extends WidgetComponent implements OnInit {
constructor() {
super();
}
ngOnInit(): void {
}
}
Problem med den nuvarande metoden: Det finns en widgetName statisk egenskap i varje komponent men dessa komponenter tvingas inte att åsidosätta denna widgetName egenskap.
Än en gång, finns det något sätt att tvinga en klass att implementera/överskrida en statisk variabel?
Svar #1
Du kan inte ha abstrakta statiska medlemmar, och du kan inte ha abstrakta dataprodukter. :-|
Jag ser tre alternativ, av vilka jag tror att jag tycker mest om det tredje (men jag började med bara två, så jag lade till det i slutet):
Gör det till en abstrakt prototypfunktion som returnerar widgetens namn.
Gör det till en abstrakt prototyp-getter (åtkomstfunktion) som returnerar widgetens namn. Du får åtkomst till detta precis som en dataproperty, men det är ett dolt funktionsanrop.
Gör typen på komponenten till en union av en basklass och
{widgetName: string;}.
Av de två första gör det andra det något mer uppenbart att funktionen förväntas inte göra något betydande arbete.
abstract class WidgetComponent {
abstract get widgetName(): string;
}
class Example extends WidgetComponent {
get widgetName() { return "example"; }
}
// Works, but I don't like it -- note you have to look at the prototype
console.log(Example.prototype.widgetName); // "example;
Länk till lekplats
Eller här är ett exempel på #3:
abstract class BaseWidgetComponent {
}
type WidgetComponent = BaseWidgetComponent & {widgetName: string;};
class Good extends BaseWidgetComponent {
static widgetName = "good";
}
class Bad extends BaseWidgetComponent {
}
console.log(Good.widgetName); // <== Works
console.log(Bad.widgetName); // <== Fails
Lekplatslänk
Svar #2
Du kan tvinga implementering av en statisk metod med ett gränssnitt, men såvitt jag vet kan du inte tvinga överskuggning av en statisk metod (som en abstrakt metod skulle göra). Deklarerade statiska funktioner (om några) kommer dock att överskugga den i deras superklass.
interface ClassWithStaticMethod {
staticMethod: () => void;
new (): any;
}
const Test1: ClassWithStaticMethod = class {
static staticMethod(){ console.log("Test.staticMethod called") }
}
const Test2: ClassWithStaticMethod = class extends Test1 {
}
const Test3: ClassWithStaticMethod = class extends Test1 {
static staticMethod(){ console.log("Test3.staticMethod called") }
}
function callStaticMethod (AClass: ClassWithStaticMethod){
AClass.staticMethod();
}
callStaticMethod(Test1); // Test.staticMethod called
callStaticMethod(Test2); // Test.staticMethod called
callStaticMethod(Test3); // Test3.staticMethod called
