Er det mulig i TypeScript å definere en betinget returtype og ikke bruke typekonvertering i funksjonskroppen?
Jeg prøver å korrekt angi returtypen til en funksjon basert på inndataene, og så tvinger TypeScript meg til å bruke as-nøkkelordet for å løse problemet jeg har. Finnes det en måte å unngå dette på, og finnes det en elegant løsning?
type TestReturnType<T> = T extends string ? number : string;
const test = <T,>(value: T): TestReturnType<T> => {
if (typeof value === 'string') {
return 1 as TestReturnType<T>; // ?
} else {
return '1' as TestReturnType<T>; // ?
}
};
const res1 = test('String');
const res2 = test(13123);
Svar #1
Du kan bruke funksjonsoverlasting for å oppnå dette:
type TestReturnType<T> = T extends string ? number : string;
function test(value: string): TestReturnType<string>;
function test(value: number): TestReturnType<number>;
function test<T>(value: T): TestReturnType<string | number> {
if (typeof value === 'string') {
return 1;
} else {
return '1';
}
}
const res1 = test('String'); // res1: number
const res2 = test(13123); // res2: string
Merk at,
- hvis du utelater overbelastningene, vil både
res1ogres2ha typenstring | number - du kan fjerne typeparameteren til test og erklære den som
function test(value: any)
Svar #2
Nei, for øyeblikket når en funksjon returnerer en betinget type som avhenger av en generisk typeparameter, må du bruke en typepåstand (det du kaller "typecasting") i return-linjen, eller gjøre noe tilsvarende løst typet (for eksempel overbelastning av funksjonen). Det finnes dessverre ingen måte å få kompilatorverifisert typesikkerhet på. Se microsoft/TypeScript#33912 for den relevante funksjonsforespørselen.
Problemet er at selv om kontrollflytanalyse kan brukes til å snevre inn typene til verdier av generiske typer, påvirker det ikke den generiske typeparameteren i det hele tatt. Inne i din test()-funksjon kan typeof value === "string" snevre inn value fra T til T & string, men T i seg selv endres ikke for å bli begrenset til string. Dermed kan ikke typen T extends string ? number : string evalueres som number; det er bare T extends string ? number : string.
