TypeScript - Förhindra typinferens i klasskonstruktorn
Titta på detta exempel:
class Foo<T extends string> {
constructor(bar: T) { }
}
const a = new Foo("a"); // type => Foo<"a">
const b = new Foo("b"); // type => Foo<"b">
I koden ovan kan du se att variablerna a och b har härledda typer från konstruktören, men jag skulle vilja att de båda har bokstavliga typer som jag själv anger ELLER återfall till standardvärdet som är Foo<string>. Efter att ha experimenterat kom jag fram till denna lösning:
class Foo<T extends string> {
constructor(bar: T extends string ? T : never) { }
}
const a = new Foo("a"); // type => Foo<string>
const b = new Foo("b"); // type => Foo<string>
const c = new Foo<"a" | "b" | "c">("c"); // type => Foo<"a" | "b" | "c">
const d = new Foo<"a">("c"); // error => [ts] Argument of type '"c"' is not assignable to parameter of type '"a"'. [2345]
d ger ett fel som det ska göra när typerna inte stämmer och det är precis vad jag behöver.
Vad jag vill veta är, varför gör
T extends string ? T : never
förhindra härledning? Det kokar i princip ner till true ? T : never vilket vidare kokar ner till T.
Redigera 1: Det kan förenklas ytterligare:
class Foo<T extends string> {
constructor(bar: T extends T ? T : never) { }
}
Redigera 2: KeepType verkar fungera med vad som helst så länge det angivna T inte är utökat (standardtypen kommer att vara vad du väljer och du kommer fortfarande få ett fel om du gör fel):
type KeepType<T> = T extends T ? T : never; // Only works when T is not extending anything
class Foo<T = unknown> {
constructor(bar: KeepType<T>) { }
}
const a = new Foo("a"); // type => Foo<unknown>
const b = new Foo("b"); // type => Foo<unknown>
const c = new Foo<"a" | "b" | "c">("c"); // type => Foo<"a" | "b" | "c">
const d = new Foo<"a">("c"); // error => [ts] Argument of type '"c"' is not assignable to parameter of type '"a"'. [2345]