node.js - Typescript: Overstyre statisk fabrikkmetode til foreldreklasse i barneklassemetode
Jeg støter på noen problemer med avhengighetsinjeksjon i Typescript. På hver klasse legger jeg til en fabrikkmetode som statisk hvor alle avhengigheter settes. Jeg gjør dette for testformål slik at jeg fortsatt kan bruke TDD-tilnærmingen.
Nå støter jeg på noen problemer med å overstyre fabrikkmetoden til foreldrekassen i en barnekasse. Eksempel:
interface DepsA {
a: string
}
interface DepsB extends DepsA {
b: Child1
}
class Parent {
constructor(protected deps: DepsA | DepsB) {}
public static factory<T extends Parent>() {
return new this({a: 'This is a nice Dependency'}) as T
}
}
class Child1 extends Parent {}
class Child2 extends Parent {
public static factory() {
return new this({a: 'This is a nice Dependency', b: Child1.factory()})
}
}
const child1 = Child1.factory<Child1>()
const child2 = Child2.factory()
Feilen jeg mottar er:
[ts]
Class static side 'typeof Child2' incorrectly extends base class static side 'typeof Parent'.
Types of property 'factory' are incompatible.
Type '() => Child2' is not assignable to type '<T extends Parent>() => T'.
Type 'Child2' is not assignable to type 'T'.
Jeg vet hvorfor jeg får feilen, men har på dette tidspunktet ingen idé lenger om hvordan jeg skal fikse det, annet enn å gi nytt navn til fabrikksmetoden i Child2.
OPPDATERING: En relatert feilrapport til dette problemet, som forklarer automatisk hvorfor jeg bruker en Generisk på fabrikksmetoden, er: #26298
Svar #1
Først finnes det en forhåndsdefinert betinget type kalt InstanceType som kan hjelpe deg med å utlede klassetypen fra det statiske medlemmet:
public static factory<T extends typeof Parent>(this: T) {
return new this({ a: 'This is a nice Dependency' }) as InstanceType<T>
}
For det andre, hvis du overstyrer en metode, statisk eller ikke, i en barneklasse, bør den ha en kompatibel signatur, inkludert de generiske tingene.
Følgelig kan kodeblokken din se slik ut (se i Typescript Playground):
interface DepsA {
a: string
}
interface DepsB extends DepsA {
b: Child1
}
class Parent {
constructor(public deps: DepsA | DepsB) {}
public static factory<T extends typeof Parent>(this: T) {
return new this({ a: 'This is a nice Dependency' }) as InstanceType<T>
}
}
class Child1 extends Parent {}
class Child2 extends Parent {
public static factory<T extends typeof Parent>(this: T) {
return new this({a: 'This is a nice Dependency', b: Child1.factory()}) as InstanceType<T>
}
}
const child1 = Child1.factory() // Type: Child1
const child2 = Child2.factory() // Type: Child2
Derfra vil det også være mulig å returnere riktig deps-type, i stedet for en union, i ikke-statiske medlemmer, ved å bruke as this["deps"]. Men du må omstrukturere koden din litt.
Håper det hjelper ;-)
