Standardparametrar med generiska typer i TypeScript
Överväg det sista exemplet på generics från TypeScript-dokumentationen: https://www.typescriptlang.org/docs/handbook/generics.html#using-class-types-in-generics
Om jag ville göra Lion till standardvärdet för createInstance(), hur skulle jag göra detta?
Till exempel:
class Animal {
numLegs: number = 0;
}
class Lion extends Animal {
keeper = "zookeeper";
}
function createInstance<A extends Animal>(c: new () => A = Lion): A { // error!
// -------------------------------------> ~~~~~~~~~~~~~~~~~~~~~
// 'Lion' is assignable to the constraint of type 'A', but 'A' could be
// instantiated with a different subtype of constraint 'Animal'.
return new c();
}
Lekplatslänk
Svar #1
Det finns för närvarande inget sätt att göra detta med kompilatorverifierad typ-säkerhet. Se microsoft/TypeScript#58977 för den relevanta funktionens begäran. Just nu innebär alla tillvägagångssätt att man arbetar runt denna begränsning.
Du kan använda en generisk parameterstandard och en typering för att tala om för kompilatorn att en brist på inferens för A innebär att A är Lion, och att det är okej att göra den antagelsen:
function createInstanceAssert<A extends Animal = Lion>(c: new () => A = Lion as any) {
return new c();
}
Detta kommer att fungera som önskat i dina användningsfall, tror jag:
createInstanceAssert(Lion).keeper.nametag;
createInstanceAssert(Bee).keeper.hasMask;
createInstanceAssert().keeper.nametag;
Även om det finns möjlighet för någon att manuellt specificera den generiska parametern och orsaka problem:
createInstanceAssert<Bee>().keeper.hasMask.valueOf(); // compiles, but error at runtime
// ---------------> ~~~~~ don't do this, okay?
Det är förmodligen inte sannolikt, men du bör vara medveten om det.
Om du verkligen vill förhindra missbruk kan du använda överlagringar för att skilja de två separata användningsfallen:
function createInstanceOverload<A extends Animal>(c: new () => A): A;
function createInstanceOverload(): Lion;
function createInstanceOverload(c: new () => Animal = Lion) {
return new c();
}
Du kan i princip kalla på det med en parameter, i vilket fall det är generiskt och A härleds, eller så kan du kalla på det utan parameter, i vilket fall det inte är generiskt, och en Lion kommer ut:
createInstanceOverload(Lion).keeper.nametag;
createInstanceOverload(Bee).keeper.hasMask;
createInstanceOverload().keeper.nametag;
Eftersom det inte finns någon generell noll-arg-anropssignatur är följande inte längre möjligt utan ett stort kompilatorfel:
createInstanceOverload<Bee>().keeper.hasMask.valueOf(); // error at compile time
Lekplatslänk till kod
