ProgrammatieFrontend/Fullstack ontwikkelaar

Hoe werkt het type ReturnType<T> in TypeScript, wat is het verschil met handmatige type-afleiding van de retourwaarde van een functie, en wat zijn de risico's/voordelen bij het gebruik ervan?

Slaag voor sollicitatiegesprekken met de Hintsage AI-assistent

Antwoord.

Achtergrond

Met de ontwikkeling van TypeScript ontstond de noodzaak om automatisch het type van de retourwaarde van een functie te extraheren, vooral voor grote projecten met veel onderling verbonden functies. Hiervoor werd het hulptype ReturnType<T> geïntroduceerd, dat beschikbaar kwam in de standaardbibliotheek vanaf versie TypeScript 2.8.

Probleem

In grote en complexe projecten kan het moeilijk zijn om de types actueel te houden — als je handmatig het type van de retourwaarde van elke functie opgeeft en de handtekeningen wijzigt, kan er gemakkelijk een inconsistentie ontstaan wanneer de handtekeningen en implementaties niet overeenkomen. Bovendien, als een functie een complexe structuur retourneert, is het niet altijd eenvoudig om de beschrijving van het teruggegeven type handmatig in alle gebruiksplaatsen te synchroniseren.

Oplossing

Het hulptype ReturnType<T> extrahert automatisch het retourtype van functies en kan worden gebruikt voor het typeren van het resultaat van een functieaanroep op elke plek in de code. Dit vermindert de hoeveelheid handmatige onderhoud aan de type-infrastructuur en minimaliseert fouten die verband houden met inconsistentie tussen het beschreven en feitelijke retourtype.

Voorbeeldcode:

function createUser(name: string, age: number) { return { name, age, created: new Date() }; } type User = ReturnType<typeof createUser>; // User: { name: string; age: number; created: Date; }

Belangrijkste kenmerken:

  • Extraheert automatisch het type van de retourwaarde van functies (inclusief generics), waardoor duplicatie van code wordt vermeden.
  • Vermindert de kans op fouten bij wijziging van de handtekening van de functie of de structuur van de retourwaarde.
  • Werkt niet met functie-overbelastingen — extraheert alleen het algemene (brede) retourtype.

Lastige vragen.

Kan ReturnType worden gebruikt met klasse-methoden?

Ja, maar het is belangrijk om rekening te houden met de context: als de methode een eigenschap van een object is met een functie, gebruik dan ReturnType<obj['methode']>.

Voorbeeldcode:

class MyClass { foo(x: number) { return x * 2; } } type FooReturn = ReturnType<MyClass['foo']>; // Type-error! // Het moet zijn: type FooReturn = ReturnType<(x: number) => number>; // number // Of de methode als functie buiten de klasse plaatsen: const obj = new MyClass(); type FooReturn2 = ReturnType<typeof obj.foo>;

Wat zal ReturnType teruggeven voor functies met void/never?

Voor een functie met een opgegeven type void, zal ReturnType void teruggeven. Voor never — never.

Voorbeeldcode:

function doNothing(): void {} type Result = ReturnType<typeof doNothing>; // void

Werkt ReturnType met functie-overbelastingen?

Nee, ReturnType extraheert het retourtype van de "implementatie" zelf, niet van alle overbelastingen. Als er meerdere overbelastingen zijn, wordt het beschreven type van de implementatie genomen.

Voorbeeldcode:

function func(x: number): number; function func(x: string): string; function func(x: any): any { return x } type RT = ReturnType<typeof func>; // any

Typfouten en anti-patronen

  • Het gebruik van ReturnType met overbelastingen van functies leidt tot onverwachte types.
  • Vergeten dat ReturnType de retourtypewaarde van Promise niet berekent — Awaited of handmatige verwerking is nodig.
  • Volledig vertrouwen op ReturnType bij wijziging van de logica van de functie zonder andere afhankelijke delen van de code bij te werken.

Voorbeeld uit de praktijk

Negatief geval

In een project wordt een handmatig type voor het teruggegeven object van een functie gedeclareerd. De functie verandert — het type wordt niet bijgewerkt, aanroepen falen in runtime.

Voordelen:

  • Types zijn gemakkelijk te lezen, kunnen handmatig worden geregeld.

Nadelen:

  • Verouderen snel, er ontstaat een "drift" tussen de types en de feitelijke API.

Positief geval

Ze schakelen overal over naar ReturnType waar ze waarden gebruiken die door functies worden geretourneerd. In geval van wijzigingen is het type altijd actueel.

Voordelen:

  • Minimale duplicatie, getypeerde overeenstemming met de feitelijke implementatie.

Nadelen:

  • Er kunnen moeilijkheden ontstaan bij het begrijpen van de type magie voor nieuwkomers.