🎅 Advent of TypeScript 2024 - Jour 14
🎅Santa Hides Behind Perf Review - typage de générateurs asynchrones
https://www.adventofts.com/events/2024/14
Aujourd'hui on s'attaque au typage d'un générateur asynchrone. Encore une des fonctionnalités de JavaScript que je n'utilise jamais. Probablement parce-que j'ai appris le JS à une époque où ça n'existait pas, et que je n'ai pas encore appris à penser les problèmes avec ce prisme.
Donc forcément, si je connais le principe des générateurs asynchrones en JS, je ne sais pas du tout comment on peut typer tout ça. Mais l'avantage de cet exercice, c'est qu'il n'y a pas besoin d'y connaitre grand chose pour en venir à bout !
Solution
Si on regarde dans les tests, on voit déjà une erreur :
type t0_actual = PerfReview < ReturnType < t0_type >> ;Type 'PerfReview' is not generic.2315Type 'PerfReview' is not generic.
On peut donc changer la définition de PerfReview
en :
type PerfReview <T > = unknown;
Maintenant on voit que l'erreur se situe bien au niveau du test. En effet, t0_actual
et t0_expected
n'ont pour le moment rien à voir.
type t0_type = typeof numberAsyncGenerator ;type t0_actual = PerfReview <ReturnType <t0_type >>;type t0_expected = 1 | 2 | 3;
Pour ce test, on sait au moins que le T
qui sera passé à PerfReview
sera ReturnType<t0_type>
. Si on l'évalue on voit ça :
type _ = ReturnType <t0_type >
Le problème peut donc être reformulé ainsi :
Si on passe
AsyncGenerator<1 | 2 | 3, void, unknown>
en paramètre de type àPerfReview
, il doit retourner1 | 2 | 3
(t0_expected
)
Tout de suite, c'est bien plus simple, car il suffit d'un infer
pour aller extraire ce premier paramètre de type d'AsyncGenerator
! On créé donc un type conditionnel pour pouvoir utiliser le infer
en commençant la définition par T extends AsyncGenerator<1 | 2 | 3, void, unknown> ? ...
, puis on remplace la valeur qu'on doit extraire par le infer
: T extends AsyncGenerator<infer R, void, unknown> ? ...
, et enfin on retourne notre type inféré R
, sinon on retourne never
, comme c'est très souvent le cas dans les types conditionnels.
type PerfReview <T > = T extends AsyncGenerator <infer R , void, unknown> ? R : never;
Et juste avec cette démarche, sans aucun prérequis sur les générateurs asynchrones ou leur types, on a résolu le problème du jour. Ce qui ne veut pas dire qu'il ne faudrait pas aller se renseigner dessus hein, je met ça dans ma TODO 😏
À demain ! 🎄