Le structurel rend un Email validé et un string brut interchangeables.Structural typing makes a validated Email and a raw string interchangeable.
C'est le revers du Vol 1 : la compatibilité se décide sur la forme. Un email validé a la forme d'un string — donc il EST un string, et n'importe quel string passe là où on attend un email. Résultat : on revalide partout, ou pire, on oublie. La question du volume, poussée à son sommet : cet invariant que je revérifie sans cesse, puis-je le rendre impossible à ne pas avoir prouvé ?It's the flip side of Vol 1: compatibility is decided on shape. A validated email has the shape of a string — so it IS a string, and any string passes where an email is expected. The result: you re-validate everywhere, or worse, you forget. The volume's question, pushed to its summit: this invariant I keep rechecking, can I make it impossible to hold without having proven?
type Email = string; // ✗ juste un alias : Email EST string, structurellement function sendTo(to: Email) { /* ... */ } sendTo("pas-un-email"); // compile — aucun email validé n'est exigé sendTo(formInput.value); // compile — string brut du dehors, jamais vérifié
Avec un simple alias, sendTo accepte tout string : la validation est une promesse orale. Le brand referme la porte — on ne tient un Email qu'en l'ayant prouvé.With a plain alias, sendTo accepts any string: validation is a spoken promise. The brand shuts the door — you only hold an Email by having proven it.
type Email = string & { readonly __brand: "Email" }; function parseEmail(raw: string): Email | null { return /^[^@]+@[^@]+$/.test(raw) ? (raw as Email) : null; } function sendTo(to: Email) { /* ... */ } sendTo("pas-un-email"); // ✗ string n'est PAS assignable à Email const e = parseEmail(input); if (e) sendTo(e); // ✓ seul un Email prouvé franchit la porte
« Cet invariant que je revérifie partout — puis-je le rendre impossible à ne pas avoir prouvé ? » Si une valeur n'est valide qu'après un contrôle, encode ce contrôle dans son type : un brand qu'on n'obtient qu'en passant par le validateur."This invariant I recheck everywhere — can I make it impossible to hold without having proven?" If a value is only valid after a check, encode that check into its type: a brand you obtain only by going through the validator.
Le 3.1 rendait une mauvaise combinaison de formes irreprésentable ; le 3.2, un cas oublié impossible. Le 3.3 s'attaque à la dernière maille : la valeur de la bonne forme mais du mauvais contenu — un string qui ressemble à un email sans en être un. On pousse l'invariant jusque dans une valeur primitive.3.1 made a bad combination of shapes unrepresentable; 3.2, a forgotten case impossible. 3.3 tackles the last link: the value of the right shape but the wrong content — a string that looks like an email without being one. We push the invariant down into a primitive value.