typescript - Begränsa typ efter superklass i gränssnitt
Jag skulle vilja skapa ett gränssnitt som definierar en uppsättning nyckel-värde-par där värdet är begränsat till en typ av klass som utökar en specifik superklass.
Till exempel detta gränssnitt:
interface MyInterface {
key: typeof SuperClass
}
och denna basklass:
class BaseClass extends SuperClass {...}
Tillämpad på detta sätt:
function myFunction(arg: MyInterface) {...};
myFunction({
key: BaseClass
});
Ovanstående kod skulle berätta för mig att typeof BaseClass inte kan tilldelas typeof SuperClass.
Nu förstår jag att det jag gör inte är korrekt, men är det möjligt på något annat sätt? Jag skulle vilja säkerställa att de enda tillåtna värdena för "key" är typer av klasser som utvidgar SuperClass?
Om jag hade arbetat med funktioner skulle jag kunna använda generiska typer, men så vitt jag vet finns det inget sätt att uttrycka en generisk typ på ett objektets egenskap.
All hjälp skulle vara fantastiskt!
Svar #1
Om alla klasser som utökar SuperClass har kompatibla konstruktörparametrar, bör din kod fungera utan fel. Till exempel:
class SuperClass {
superValue: string;
}
interface MyInterface {
key: typeof SuperClass
}
class BaseClass extends SuperClass {
baseValue: string;
}
function myFunction(arg: MyInterface) { };
myFunction({
key: BaseClass // no error
});
Det finns inget problem här eftersom både BaseClass och SuperClass kan konstrueras med noll argument. Men om du ändrar konstruktorn för BaseClass:
class BaseClass extends SuperClass {
baseValue: string;
constructor(someArgument: string) {
super();
}
}
du kommer att få det fel du nämnde när du anropar myFunction():
Argument of type '{ key: typeof BaseClass; }' is not assignable to parameter of type 'MyInterface'.
Types of property 'key' are incompatible.
Type 'typeof BaseClass' is not assignable to type 'typeof SuperClass'.
Nu, beroende på vad du vill göra med MyInterface, kan det felet vara viktigt. Avser du att ta key-egenskapen hos ett MyInterface-värde och använda det för att skapa en instans av någon underklass till SuperClass? Till exempel:
declare let myInterface: MyInterface;
let someInstance = new myInterface.key();
Om så är fallet behöver du se till att klasskonstruktorn accepterar rätt antal och typ av argument, och att felet hjälper dig. Det talar om för dig att ändra BaseClass-konstruktorn för att vara kompatibel med SuperClass-konstruktorn. Till exempel, om vi gör someArgument valfritt:
class BaseClass extends SuperClass {
baseValue: string;
constructor(someArgument?: string) {
super();
}
}
då försvinner felet eftersom new SubClass() nu fungerar utan några argument.
Om du inte avser att använda MyInterface för att skapa instanser, och du inte bryr dig om antalet och typen av argument som konstruktörerna tar, och du bara vill att det ska hålla någon klasskonstruktör av någon anledning... då kan du göra så här:
type Constructor<T> = {
new(...args: any[]): T; // any number and type of arguments
}
interface MyInterface {
key: Constructor<SuperClass>
}
Nu kommer myFunction() att fungera även om konstruktörssignaturerna är inkompatibla. Det beror på att du egentligen inte vill begränsa dig till typeof SuperClassvilken som helst konstruktör som skapar en SuperClass, och det är vad Constructor<SuperClass> betyder. Så felet försvinner och du blir nöjd.
Förhoppningsvis kommer en av de två lösningarna att fungera för dig. Lycka till!
