generics - TypeScript diskriminerad unionstyp med standardvärde och typinferens
Jag vill skapa en diskriminerad unionstyp, där det inte är nödvändigt att ange diskriminatorvärdet.
Här är min nuvarande kod:
interface Single<T> {
multiple?: false // this is optional, because it should be the default
value: T
onValueChange: (value: T) => void
}
interface Multi<T> {
multiple: true
value: T[]
onValueChange: (value: T[]) => void
}
type Union<T> = Single<T> | Multi<T>
För testning använder jag detta:
function typeIt<T>(data: Union<T>): Union<T> {
return data;
}
const a = typeIt({ // should be Single<string>
value: "foo",
onValueChange: (value) => undefined // why value is of type any?
})
const b = typeIt({ // should be Single<string>
multiple: false,
value: "foo",
onValueChange: (value) => undefined
})
const c = typeIt({ // should be Multi<string>
multiple: true,
value: ["foo"],
onValueChange: (value) => undefined
})
Men jag får en massa fel och varningar...:
I
const a'sonValueChangeär typen av parameternvalueany. När man sättermultiple: falseuttryckligen (som iconst b) härleds den korrekt somstring.const cfungerar inte alls. Jag får detta fel: "Typen 'string' kan inte tilldelas typen 'string[]'".
Har du någon aning om hur man löser det här?
Jag har skapat en TypeScript Playground med denna kod
Svar #1
Jag tror inte att kompilatorn enkelt kan härleda typen av value-parametern i callbacken eftersom typen av objektliteralen fortfarande inte är bestämd när callbacken kontrolleras.
Om du inte har många fackmedlemmar är en lösning som fungerar som förväntat att använda flera överlagringar:
export interface Single<T> {
multiple?: false // this is optional, because it should be the default
value: T
onValueChange: (value: T) => void
}
interface Multi<T> {
multiple: true
value: T[]
onValueChange: (value: T[]) => void
}
type Union<T> = Single<T> | Multi<T>
function typeIt<T>(data: Single<T>): Single<T>
function typeIt<T>(data: Multi<T>): Multi<T>
function typeIt<T>(data: Union<T>): Union<T> {
return data;
}
const a = typeIt({ // is Single<string>
value: "foo",
onValueChange: (value) => undefined // value is typed as expected
})
const b = typeIt({ // is Single<string>
multiple: false,
value: "foo",
onValueChange: (value) => undefined
})
const c = typeIt({ // is be Multi<string>
multiple: true,
value: ["foo"],
onValueChange: (value) => undefined
})
