Typ konštruktora triedy v TypeScripte?
Ako môžem deklarovať typ class, aby som zabezpečil, že objekt je konštruktorom všeobecnej triedy?
V nasledujúcom príklade chcem vedieť, aký typ by som mal dať AnimalClass, aby to mohlo byť buď Penguin alebo Lion:
class Animal {
constructor() {
console.log("Animal");
}
}
class Penguin extends Animal {
constructor() {
super();
console.log("Penguin");
}
}
class Lion extends Animal {
constructor() {
super();
console.log("Lion");
}
}
class Zoo {
AnimalClass: class // AnimalClass could be 'Lion' or 'Penguin'
constructor(AnimalClass: class) {
this.AnimalClass = AnimalClass
let Hector = new AnimalClass();
}
}
Samozrejme, typ class nefunguje a aj tak by bol príliš všeobecný.
Odpoveď č. 1
Úprava: Táto otázka bola zodpovedaná v roku 2016 a je čiastočne zastaraná. Pozrite si aktuálnu odpoveď od @Nenad nižšie.
Riešenie z referencie rozhraní TypeScript:
interface ClockConstructor {
new (hour: number, minute: number): ClockInterface;
}
interface ClockInterface {
tick();
}
function createClock(ctor: ClockConstructor, hour: number, minute: number): ClockInterface {
return new ctor(hour, minute);
}
class DigitalClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("beep beep");
}
}
class AnalogClock implements ClockInterface {
constructor(h: number, m: number) { }
tick() {
console.log("tick tock");
}
}
let digital = createClock(DigitalClock, 12, 17);
let analog = createClock(AnalogClock, 7, 32);
Tak predchádzajúci príklad sa stáva:
interface AnimalConstructor {
new (): Animal;
}
class Animal {
constructor() {
console.log("Animal");
}
}
class Penguin extends Animal {
constructor() {
super();
console.log("Penguin");
}
}
class Lion extends Animal {
constructor() {
super();
console.log("Lion");
}
}
class Zoo {
AnimalClass: AnimalConstructor // AnimalClass can be 'Lion' or 'Penguin'
constructor(AnimalClass: AnimalConstructor) {
this.AnimalClass = AnimalClass
let Hector = new AnimalClass();
}
}
Odpoveď č. 2
Nie som si istý, či to bolo možné v TypeScript, keď sa otázka pôvodne položila, ale moje preferované riešenie je s generikami:
class Zoo<T extends Animal> {
constructor(public readonly AnimalClass: new () => T) {
}
}
Týmto spôsobom premenné penguin a lion odvodzujú konkrétny typ Penguin alebo Lion dokonca aj v TypeScript intellisense.
const penguinZoo = new Zoo(Penguin);
const penguin = new penguinZoo.AnimalClass(); // `penguin` is of `Penguin` type.
const lionZoo = new Zoo(Lion);
const lion = new lionZoo.AnimalClass(); // `lion` is `Lion` type.
Odpoveď č. 3
Takto:
class Zoo {
AnimalClass: typeof Animal;
constructor(AnimalClass: typeof Animal ) {
this.AnimalClass = AnimalClass
let Hector = new AnimalClass();
}
}
Alebo len:
class Zoo {
constructor(public AnimalClass: typeof Animal ) {
let Hector = new AnimalClass();
}
}
typeof Class je typ konštruktora triedy. Je to vhodnejšie ako vlastné deklarovanie typu konštruktora, pretože správne spracuje statické členy triedy.
Tu je relevantná časť dokumentácie TypeScriptu. Vyhľadajte typeof. Ako súčasť anotácie typu v TypeScripte to znamená „dajte mi typ symbolu nazvaného Animal“, ktorý je v našom prípade typom konštrukčnej funkcie triedy.
Odpoveď č. 4
Ako môžem deklarovať typ triedy, aby som zabezpečil, že objekt je konštruktorom všeobecnej triedy?
Typ konštruktora by mohol byť definovaný ako:
type AConstructorTypeOf<T> = new (...args:any[]) => T;
class A { ... }
function factory(Ctor: AConstructorTypeOf<A>){
return new Ctor();
}
const aInstance = factory(A);
