Journal
Sections
Réglages de lecture
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
Code et termes techniques en anglais
Désactivé : la voix de la page lit tout, sans pause entre deux voix.
Aucune voix pour cette langue dans ce navigateur.
Plus de voix
D’autres voix : Microsoft Edge propose des voix naturelles en ligne, et Windows (Paramètres › Heure et langue › Voix), macOS et Android en installent d’autres.
Progression
Section intitulée « Progression »- Le projet du cours : TypeScript 7.0.2, Zod 4.6.5, Valibot 1.5.0, ArkType 2.2.3 et esbuild 0.28.2 épinglés dans son propre
package.jsonet son propre fichier de verrouillage -
check.sh: tests de types, extraits d’erreur, exemples et solutions exécutés avec Node.js 24.21.0, tailles de bundle, comparaisons C# et Java, le tout comparé avecexpected/ - CI sous Linux, Windows et macOS
- Leçon 1 : programmation au niveau des types
- Leçon 2 : variance et assignabilité
- Leçon 3 : modéliser avec les types
- Leçon 4 : frontières à l’exécution
- Leçon 5 : fichiers de déclaration
Le compilateur TypeScript, .NET 10 et deux bibliothèques de validation. Plusieurs lignes décrivent un comportement documenté dans lequel une intuition vient se jeter, et la colonne État le dit. Les constantes du vérificateur ont été lues dans checker.go au commit épinglé avant d’être mesurées. Rien n’a été signalé en amont.
| Attendu | Ce qui se passe | Où | Mesure | État |
|---|---|---|---|---|
| Une limite de récursion au niveau des types est une propriété du type | C’est une propriété du fichier : les instanciations sont mises en cache, donc ce qui passe dépend de ce que le fichier a évalué avant | tsc 7.0.2, un Reverse non terminal |
48 éléments passent et 49 échouent quand il est seul dans le fichier ; avec un Reverse de 40 évalué d’abord dans le même fichier, 80 passent |
Reproduit ; une limite mesurée dans un fichier n’est pas une limite pour un autre 2026-09-15 |
Un type contextuel en littéral de gabarit élargit les littéraux vers string |
Il les conserve : un type littéral de gabarit compte comme un contexte littéral | tsc 7.0.2, satisfies Record<GovernanceHealthStatus, HexColor> |
Seul un type contextuel comme string les élargit |
Par conception, et l’inverse de ce qu’attendait l’auteur 2026-09-15 |
Un paramètre de type const contraint par un tableau mutable retombe sur string[] |
Il infère un tuple mutable | tsc, vérifié contre 5.0.4, 5.2.2 et 5.3.3 | Vrai de la 5.0 à la 5.2 ; changé en 5.3. La frontière a été située en bissectant trois versions épinglées | Reproduit ; un changement de comportement, correctement attribué 2026-09-15 |
in out T sur un type qui ne fait que lire T est refusé |
Il est accepté, parce que in out rend un type invariant, ce qui est toujours sûr |
tsc 7.0.2 | Seule une annotation qui contredit la structure échoue, en TS2636 |
Par conception 2026-09-15 |
Un as vers un type auquel il manque des propriétés est rejeté partout pareil |
En direct, c’est TS2352 ; en passant par une variable, les types sont comparables et cela compile |
tsc 7.0.2 | La seconde forme est celle qu’on trouve dans du vrai code, et c’est celle que montre la leçon 2 | Par conception ; la moitié dangereuse est la silencieuse 2026-09-15 |
dotnet run file.cs peut sérialiser un type anonyme |
Il échoue à l’exécution | programmes .NET 10 en fichier unique | Reflection-based serialization has been disabled for this application, parce que ces programmes se publient en AOT natif par défaut. #:property PublishAot=false le rétablit |
Reproduit, non signalé 2026-09-15 |
System.Text.Json respecte par défaut les annotations de nullabilité et d’obligation |
RespectNullableAnnotations et RespectRequiredConstructorParameters, tous deux ajoutés en .NET 9, sont désactivés par défaut |
System.Text.Json, .NET 9+ |
Une fois activés, le record C# devient un schéma | Par conception ; c’est le défaut qui surprend 2026-09-15 |
| Importer un validateur élague ce qu’on n’utilise pas | L’import de baril, non : z est un objet qui référence toutes les fonctions |
Zod 4.6.5 empaqueté par esbuild 0.28.2, minifié | 442,7 ko avec import { z } from 'zod' contre 87,4 ko avec import * as z from 'zod' |
Reproduit ; la forme à espace de noms est aussi celle de la documentation 2026-09-15 |
| Des validateurs du même schéma ont des tailles comparables | Non | Valibot 1.5.0, zod/mini, Zod 4.6.5 |
Valibot 4,8 ko minifié, environ 18 fois plus petit que Zod ; zod/mini environ 5 fois plus petit |
Mesuré sous Windows, non signalé 2026-09-15 |
JsonHubProtocol a besoin d’un serveur qui tourne pour montrer ce que SignalR envoie |
Non | SignalR d’ASP.NET Core | WriteMessage sur un InvocationMessage donne le texte exact, ce qui a tranché ce que le hub de GA met sur le fil sans le démarrer |
Une technique, pas un défaut — et c’est ce qui a permis de répondre hors ligne à une question de navigateur 2026-09-15 |
Expériences
Section intitulée « Expériences »Dans ce cours, une prédiction est une ligne de code : type _1 = Expect<Equal<…>>, que tsc vérifie avec le reste du projet, si bien qu’une prédiction fausse fait échouer check.sh avant que quoi que ce soit ne s’exécute. Quatre de ces six étaient fausses, et la section que le journal leur consacre s’appelle justement les prédictions que les tests de types ont démenties. La dernière ligne est la seule où le test a suivi le soupçon, et elle le dit.
| Question | Hypothèse | Résultat | Verdict | Où |
|---|---|---|---|---|
| Les constantes du vérificateur prédisent-elles où le code au niveau des types échoue vraiment ? | Lues d’abord dans checker.go : 100 instanciations imbriquées, 5 000 000 dans une expression, 1 000 pas pour un type conditionnel terminal, 100 000 membres pour une union en produit cartésien |
Un constructeur de tuple terminal atteint 999 et échoue à 1 000 en TS2589 ; une union de cinq positions de chiffres, 100 000 chaînes, échoue en TS2590. Les mesures concordent |
Confirmée | 2026-09-15 |
Où échoue un Reverse non terminal ? |
Présentée comme difficile à prédire, et implicitement comme ayant un seul nombre pour réponse | 48 passent et 49 échoue quand il est seul dans le fichier ; 80 passent si un Reverse de 40 éléments est évalué d’abord dans le même fichier, les instanciations étant mises en cache |
L’idée d’un nombre unique est réfutée | 2026-09-15 |
satisfies Record<GovernanceHealthStatus, HexColor> élargit-il les couleurs vers string ? |
Oui, écrite avant l’exécution du test de types | Il conserve les types littéraux : un type littéral de gabarit en type contextuel compte comme un contexte littéral | Réfutée, par une compilation en échec | 2026-09-15 |
Un paramètre de type const contraint par un tableau mutable retombe-t-il sur string[] ? |
Oui, écrite avant l’exécution du test de types | Il infère un tuple mutable. L’attente valait de la 5.0 à la 5.2 et a changé en 5.3, vérifié contre 5.0.4, 5.2.2 et 5.3.3 | Réfutée, et la frontière de version située | 2026-09-15 |
in out T est-il refusé sur un type qui ne fait que lire T ? |
Oui, écrite avant l’exécution du test de types | Accepté : in out rend un type invariant, ce qui est toujours sûr. Seule une annotation contradictoire échoue, en TS2636 |
Réfutée | 2026-09-15 |
Le as de stopFrom cache-t-il quelque chose ? |
Soupçonné, mais le test de types a été ajouté après — cette ligne est la seule entrée rétrospective du tableau | EventOf<LiveState> vaut never : l’assertion masquait que l’état stopped n’a pas d’événement stop. La fonction prend désormais Exclude<LiveState, 'stopped'>, sans assertion |
Réfutée, après coup | 2026-09-15 |
2026-09-15 — Le projet du cours
Section intitulée « 2026-09-15 — Le projet du cours »- Le cours a son propre
package.json, distinct de celui du cours de base, avec les mêmes versions de TypeScript et de Node.js : 7.0.2 et 24.21.0. Letsconfig.jsonajouteexactOptionalPropertyTypesetnoUncheckedIndexedAccessàstrict, puisque la leçon 2 dépend de la première, et gardeerasableSyntaxOnlypour que Node.js exécute chaque exemple directement, sans étape de build. - Les tests de types vivent dans les exemples : des lignes
type _1 = Expect<Equal<…>>quetscvérifie avec tout le projet. Une prédiction fausse fait échouercheck.shavant que quoi que ce soit ne s’exécute, ce qui est arrivé plusieurs fois pendant l’écriture des leçons 1 à 3, comme le liste la suite. check.shest le script du cours de base avec deux ajouts :bundle-size.mjs, dont la sortie est comparée comme les autres, et des comparaisons C# qui référencent ASP.NET Core avec#:sdk Microsoft.NET.Sdk.Web.- Le dépôt de GA ne s’extrait pas entièrement sous Windows : les dossiers
test-results/de Playwright sont commités, avec des chemins de plus de 260 caractères. Un clone partiel (sparse) des dossiers qu’utilisent les leçons, avecgit config core.longpaths true, fonctionne.
2026-09-15 — Les limites du vérificateur, mesurées
Section intitulée « 2026-09-15 — Les limites du vérificateur, mesurées »- Les limites sont des constantes de
internal/checker/checker.go: 100 instanciations imbriquées et 5 000 000 dans une même expression, 1 000 étapes pour un type conditionnel récursif terminal, et 100 000 membres pour une union construite par un produit cartésien. - Les mesures concordent : un constructeur de tuple récursif terminal atteint 999 éléments et échoue à 1 000 avec
TS2589; une union de cinq positions de chiffres, 100 000 chaînes, échoue avecTS2590. - Un
Reversequi n’est pas récursif terminal est plus difficile à prédire. Seul dans son fichier, 48 éléments passent et 49 échouent. Avec unReversede 40 éléments évalué d’abord dans le même fichier, 80 éléments passent : les instanciations sont mises en cache, et la seconde évaluation part des résultats de la première. Une limite au niveau des types mesurée dans un fichier n’est pas une limite pour un autre fichier.
2026-09-15 — Les prédictions que les tests de types ont démenties
Section intitulée « 2026-09-15 — Les prédictions que les tests de types ont démenties »- Je m’attendais à ce que
satisfies Record<GovernanceHealthStatus, HexColor>, oùHexColorest un template literal type, élargisse les couleurs enstring. Il garde les types littéraux : un template literal type utilisé comme type contextuel compte comme un contexte littéral, et seul un type contextuel commestringles élargit. - Je m’attendais à ce qu’un paramètre de type
constavec une contrainte de tableau mutable se rabatte surstring[]. C’était le comportement de 5.0 à 5.2 ; depuis 5.3, il infère un tuple mutable. J’ai vérifié avecnpx -p typescript@5.0.4,5.2.2et5.3.3. - Je m’attendais à ce que
in out Tsur un type qui ne fait que lireTsoit refusé. Il est accepté :in outrend un type invariant, ce qui est toujours sûr, et seule une annotation qui contredit la structure, commeinsur un type qui renvoieT, est une erreur (TS2636). - Dans la première version de la machine à états de la leçon 3, une fonction
stopFromutilisaitaspour quesend(state, 'stop')compile pour n’importe quel état. Le test de types que j’ai ajouté ensuite a montré queEventOf<LiveState>estnever: l’assertion cachait que l’étatstoppedn’a pas d’événementstop. La fonction prend maintenantExclude<LiveState, 'stopped'>, sans assertion. - Un littéral objet affirmé avec
asvers un type dont il n’a pas toutes les propriétés n’est pas toujours accepté : directement,tscsignaleTS2352; en passant par une variable, les types sont comparables et cela compile. La leçon 2 montre la seconde forme, qui est celle qu’on trouve dans du vrai code.
2026-09-15 — Le côté C# et Java
Section intitulée « 2026-09-15 — Le côté C# et Java »dotnet run file.cssur un fichier qui sérialise un type anonyme a échoué avec « Reflection-based serialization has been disabled for this application ». Les applications basées sur un fichier sont publiées en AOT natif par défaut, et ce réglage désactive aussi le JSON par réflexion à l’exécution ;#:property PublishAot=falsedans le fichier le rétablit.JsonHubProtocolpeut s’utiliser sans serveur :WriteMessagesur unInvocationMessagedonne le texte exact qu’envoie SignalR, ce qui a établi ce que le hub de GA met sur le fil sans avoir à le démarrer.RespectNullableAnnotationsetRespectRequiredConstructorParametersdeSystem.Text.Json, tous deux de .NET 9, sont désactivés par défaut ; avec eux, le record C# est un schéma.
2026-09-15 — Les tailles de bundle
Section intitulée « 2026-09-15 — Les tailles de bundle »- Le même schéma Zod, mis en bundle par esbuild, pèse 442,7 kB minifié avec
import { z } from 'zod'et 87,4 kB avecimport * as z from 'zod'. La différence tient au tree shaking :zest un objet qui référence toutes les fonctions. La leçon 4 garde la forme avec l’espace de noms, qui est aussi celle de la documentation. - Valibot, 4,8 kB minifié, est environ 18 fois plus petit que Zod pour ce schéma, et
zod/minienviron 5 fois. - Les tailles sont mesurées sous Windows. La sortie d’esbuild ne dépend pas de l’OS, et la CI les compare sous Linux et macOS (à vérifier une fois que le workflow aura tourné).
2026-09-15 — Ce que les leçons ont trouvé dans GuitarAlchemist/ga
Section intitulée « 2026-09-15 — Ce que les leçons ont trouvé dans GuitarAlchemist/ga »Au commit 32f143c, dans ReactComponents/ga-react-components et Apps/ga-server/GaApi/Hubs :
- Une mise à jour
NodeChangedperdue (leçon 4). Le hub envoienodeId; le client affirme que le message est unGovernanceNode, dont la clé estid;updateNodeHealthcherche le nœud paridet abandonne la mise à jour en silence. Une recherche dans le code ne trouve aucun appelant deBroadcastNodeChanged, donc le bug est latent. - Aucun contrat partagé entre le hub et le client (leçon 1). Le hub dérive de
Hub, pas deHub<T>, et envoie les noms de méthodes sous forme de chaînes ; le client enregistre dix handlers avec des chaînes. Le commentaire de documentation du hub liste un événementHealthUpdatequ’il n’envoie jamais, et l’optiononScreenshotRequestdu client gère l’événementRequestScreenshot. ViewerInfo.displayName(leçon 2) est déclarédisplayName?: stringen TypeScript et envoyé commenullpar le record C# ; le code fonctionne parce que chaque lecture utilise?.ou??.- Deux numérotations des cordes (leçon 3) : quatre interfaces nommées
FretboardPosition, toutes avecstring: number;InstrumentConfig.tsetGuitarFretboard.tsxcomptent les cordes à partir de 0, tandis queVexTabViewer.tsxetInverseKinematics.tsxprennent des numéros de corde à partir de 1. - L’état vocal de
ChatWidget.tsx(leçon 3) :isListeningetvoiceStatepeuvent se contredire ;startListeninglitvoiceStatesans le lister dans les dépendances de sonuseCallback, donc ses vérificationsvoiceState === 'listening'voient une valeur périmée ;sendMessage(…).then(…)n’a pas decatch, et une requête échouée peut laisser l’état à'processing'. - Des frontières non vérifiées (leçon 4) : 42 appels à
JSON.parse, 55 lignes qui affirment le type deresponse.json()avecas, et 34as unknown as, en dehors des tests.
Je n’ai pas signalé ces points au dépôt de GA ; ils sont listés ici tels que je les ai trouvés.
À vérifier
Section intitulée « À vérifier »- Le chemin de
NodeChangedsur un serveur en marche, si quelque chose se met à appelerBroadcastNodeChanged. - Le
voiceStatepérimé dansChatWidget.tsx, dans un navigateur avec reconnaissance vocale : une erreur pendant l’écoute devrait laisser l’indicateur sur'listening'. - Les sorties du cours sous Linux et macOS, une fois que le workflow de CI aura tourné.