TypeScript 78 termes

78 termes affichés

TypeBestPractice Concept DataStructure Pattern Tool
Niveau 🟢 Junior 🟡 Mid 🔴 Senior

Mis à jour ces 90 derniers jours 11 nouvelles · 32 révisées

--erasableSyntaxOnly

TypeScript 🟡 Mid

Option introduite en TypeScript 5.8 (28 février 2025) qui interdit toute syntaxe TypeScript nécessitant une génération de code : enum, namespace contenant du code, propriétés de paramètre de constructeur, import x = require(). Elle garantit que le fichier peut être exécuté par simple effacement des types, comme le fait Node.js (type stripping, stable en 24.12.0 et 25.2.0). La documentation Node la recommande avec verbatimModuleSyntax.

N'écrire qu'au crayon sur la copie : la gomme suffit pour retrouver le texte original.

// tsconfig.json
// { "compilerOptions": { "erasableSyntaxOnly": true, "verbatimModuleSyntax": true } }

// ❌ Refusé : nécessite du code généré
enum Statut { Actif, Inactif }
class A { constructor(private x: number) {} }

// ✅ Effaçable
const Statut = { Actif: 0, Inactif: 1 } as const;
type Statut = (typeof Statut)[keyof typeof Statut];
class B { #x: number; constructor(x: number) { this.#x = x; } }

Cas d'usage : Tout projet exécuté par node fichier.ts, Bun ou Deno sans build, ou transpilé par un outil sans typechecker.

Anti-pattern : Activer le type stripping Node sans cette option : l'erreur ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX arrive à l'exécution, pas à la compilation.
#tooling#ts5.8#node24

--isolatedDeclarations

TypeScript 🔴 Senior

Option introduite en TypeScript 5.5 (20 juin 2024) qui exige une annotation de type explicite sur chaque export dont le type ne se déduit pas trivialement. En échange, les fichiers .d.ts peuvent être générés fichier par fichier, sans vérification de type globale, donc en parallèle et par des outils non-TS (Oxc, esbuild, SWC). Pensée pour les monorepos.

Chaque colis porte son étiquette complète : n'importe quel trieur peut le router sans ouvrir les autres colis.

// tsconfig.json : { "compilerOptions": { "isolatedDeclarations": true, "declaration": true } }

// ❌ Erreur TS9007 : le type de retour doit être annoté
export function creer(n: number) { return { id: n, tags: [] }; }

// ✅ Le .d.ts se déduit sans typechecker
export function creer(n: number): { id: number; tags: string[] } {
  return { id: n, tags: [] };
}

Cas d'usage : Monorepos où la génération des .d.ts est le goulot du build ; bibliothèques publiées avec un bundler Rust.

Anti-pattern : L'activer sur une base existante d'un coup : des centaines d'erreurs ; l'introduire paquet par paquet.
#tooling#ts5.5#monorepo

--moduleResolution bundler

TypeScript 🟡 Mid

Stratégie de résolution des modules ajoutée en TypeScript 5.0 (16 mars 2023) pour les projets construits par Vite, esbuild, webpack ou Rolldown : elle comprend le champ exports et les conditions de package.json comme Node, mais tolère les imports sans extension et n'exige pas de syntaxe CommonJS. TypeScript 7.0 (8 juillet 2026) supprime les anciennes stratégies classic, node et node10 ; bundler et nodenext deviennent les deux choix courants.

Le plan de métro adapté à la ligne qu'on prend vraiment, plutôt que la carte routière nationale.

{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "noEmit": true,
    "allowImportingTsExtensions": true
  }
}

Cas d'usage : Applications front bundlées : le bundler émet le JavaScript, tsc ne fait que vérifier les types.

Anti-pattern : Utiliser bundler pour une bibliothèque exécutée directement par Node : les imports sans extension casseront à l'exécution ; prendre nodenext.
#tooling#ts5#ts7#bundler

--verbatimModuleSyntax

TypeScript 🟡 Mid

Option introduite en TypeScript 5.0 (16 mars 2023) : les imports et exports sont conservés tels qu'écrits, et seuls ceux marqués type sont supprimés. Fini l'élision implicite des imports « probablement de type » : le code émis est prévisible, ce qui est indispensable aux transpileurs fichier par fichier et au type stripping de Node.js, qui la recommande avec erasableSyntaxOnly.

Le traducteur qui rend chaque phrase mot pour mot au lieu de décider ce qui « ne sert à rien ».

// tsconfig.json : { "compilerOptions": { "verbatimModuleSyntax": true } }

import type { Utilisateur } from './types.ts';  // effacé
import { type Role, charger } from './api.ts'; // Role effacé, charger gardé

// ❌ Erreur : Utilisateur est un type, il faut `import type`
// import { Utilisateur } from './types.ts';

export type { Utilisateur };

Cas d'usage : Projets ESM modernes, bibliothèques, exécution directe par Node/Bun/Deno, builds Vite/esbuild/Oxc.

Anti-pattern : Le combiner avec des imports CommonJS déguisés (import x = require) sous module esnext : erreur de compilation.
#tooling#ts5#modules

accessor (auto-accessors)

TypeScript 🔴 Senior

Mot-clé accessor introduit en TypeScript 4.9 pour les classes : accessor x = 1 déclare un champ privé de stockage et une paire getter/setter publique sur le prototype. Il vient de la proposition TC39 Decorators (Stage 2.7 au 27 septembre 2026), où il permet aux décorateurs d'intercepter lectures et écritures, ce qu'un champ ordinaire ne permet pas.

Une boîte aux lettres avec fente et clé : on passe toujours par l'ouverture, jamais par le fond de la boîte.

function suivi<T>(cible: ClassAccessorDecoratorTarget<any, T>,
                  ctx: ClassAccessorDecoratorContext) {
  return {
    set(this: any, v: T) {
      console.log(`${String(ctx.name)} ←`, v);
      cible.set.call(this, v);
    },
  };
}
class Compteur {
  @suivi accessor valeur = 0; // get/set générés, stockage privé
}

Cas d'usage : Décorateurs de réactivité, de validation ou d'observation de propriétés (frameworks, ORM).

Anti-pattern : Utiliser accessor sans décorateur ni logique : un simple champ suffit et coûte moins.
#advanced#ts4.9#decorators

Ambient Declarations (.d.ts)

TypeScript 🟡 Mid

Fichiers de déclaration (.d.ts) qui décrivent la forme de code JavaScript existant sans implémentation. Permettent a TS de typer des libs JS.

Comme un plan architectural sans les murs réels — il décrit la structure sans la construire.

// globals.d.ts
declare const API_URL: string;
declare function legacy(x: number): string;
// Utilisable partout sans import

Cas d'usage : Typer des bibliothèques JavaScript, des variables globales injectées ou du code legacy.

Anti-pattern : Écrire des .d.ts quand on peut simplement écrire du .ts — les déclarations ne sont utiles que pour du JS pur.
#core#tooling

Assertion Function

TypeScript 🔴 Senior

Fonction avec une signature asserts qui lance une erreur si la condition n'est pas remplie. Après l'appel, le type est narrowe pour le reste du scope.

Comme un douanier qui refuse l'entrée et arrête tout si vos papiers sont invalides — pas de retour possible.

function assertString(val: unknown): asserts val is string {
  if (typeof val !== "string") throw new Error("Not string");
}
const x: unknown = getData();
assertString(x);
x.toUpperCase(); // x est string ici

Cas d'usage : Validation stricte en début de fonction qui narrowe les types pour tout le reste du bloc.

Anti-pattern : Oublier le throw dans l'assertion — la fonction ne lance pas et le narrowing est incorrect.
#advanced#safety

Awaited<T>

TypeScript 🟡 Mid

Utility type qui decompresse récursivement les Promise imbriquées pour obtenir le type de la valeur résolue finale.

Comme ouvrir des paquets cadeaux emboîtés jusqu'a trouver le vrai cadeau au centre.

type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number
type C = Awaited<string>; // string

Cas d'usage : Obtenir le type résolu d'une fonction async ou d'une chaîne de Promises pour le typage correct.

#core#utility-types

Branded / Nominal Types

TypeScript 🔴 Senior

Technique pour simuler du typage nominal en ajoutant une propriété fantôme (brand) a un type. Empêche le mélange accidentel de types structurellement identiques.

Comme des billets de différentes devises — même papier, même forme, mais on ne mélange pas des euros et des dollars.

type USD = number & { __brand: "USD" };
type EUR = number & { __brand: "EUR" };
const usd = (n: number) => n as USD;
const eur = (n: number) => n as EUR;
function pay(amount: USD) {}
pay(usd(100)); // OK
// pay(eur(100)); // Erreur

Cas d'usage : Distinguer des IDs, devises ou unités de mesure qui sont structurellement des strings/numbers.

Anti-pattern : Utiliser des types simples (string, number) pour des IDs de domaines différents — un userId passe en orderId compile sans erreur.
#advanced#pattern#safety

Builder Pattern Type

TypeScript 🔴 Senior

Implémentation du Builder pattern avec un typage qui évolue a chaque étape. Chaque méthode retourne un type plus précis, garantissant la completude a la compilation.

Comme un formulaire multi-étapes ou chaque page deverrouille la suivante — pas de raccourci possible.

class QueryBuilder<T extends object = {}> {
  select<K extends string>(col: K) {
    return this as QueryBuilder<T & Record<K, true>>;
  }
  build(): T { return {} as T; }
}
new QueryBuilder().select("name").select("age").build();

Cas d'usage : APIs fluides (query builders, form builders) ou l'ordre et la completude des appels sont critiques.

Anti-pattern : Builder sans typage progressif — rien n'empêche d'appeler build() avant d'avoir configure les champs requis.
#advanced#pattern

Conditional Types (infer)

TypeScript 🔴 Senior? entretien

Types qui sélectionnent un type selon une condition (T extends U ? X : Y). Le mot-clé infer permet d'extraire des sous-types dans la branche true.

Comme un aiguillage ferroviaire — selon le type de train, il est dirige sur une voie ou une autre.

type Unwrap<T> = T extends Promise<infer U> ? U : T;
type A = Unwrap<Promise<string>>; // string
type B = Unwrap<number>;          // number

Cas d'usage : Extraire des types imbriques (retour de Promise, éléments de tableau, props de composants React).

Anti-pattern : Imbriquer trop de conditional types — le code devient illisible et les erreurs cryptiques.
#advanced#interview#type-system

const assertion (as const)

TypeScript 🟡 Mid? entretien

Assertion qui empêche le widening et rend toutes les propriétés readonly et les valeurs littérâles. Transforme un objet/tableau en version profondément immutable.

Comme graver dans le marbre — une fois écrit, chaque détail est fige exactement tel quel.

const config = {
  api: "https://api.com",
  retries: 3
} as const;
// type: { readonly api: "https://api.com"; readonly retries: 3 }

Cas d'usage : Créer des constantes avec des types littéraux exacts pour les discriminated unions et les lookups.

Anti-pattern : Oublier as const sur des tableaux utilises comme union — ["a", "b"] donne string[] au lieu de readonly ["a", "b"].
#core#interview#best-practice

const Type Parameters

TypeScript 🟡 Mid? entretien

Modificateur const sur un paramètre générique, introduit en TypeScript 5.0 (16 mars 2023) : les arguments littéraux sont inférés comme s'ils portaient as const (tuples readonly, littéraux de chaîne), sans que l'appelant ait à l'écrire. La fonction obtient ainsi les types les plus précis possibles.

Un photographe qui capture la scène en haute définition d'office, sans que le client demande le mode RAW.

function nommer<const T extends readonly string[]>(noms: T): T { return noms; }

const a = nommer(['alice', 'bob']);
// a : readonly ['alice', 'bob']  (sans const : string[])

type Premier = (typeof a)[0]; // 'alice'
// Avant TS 5.0 : nommer(['alice', 'bob'] as const) côté appelant

Cas d'usage : Bibliothèques de routage, de validation ou de configuration typée qui veulent les littéraux exacts de l'appelant.

Anti-pattern : Mettre const partout : sur des données destinées à être mutées, on impose des readonly indésirables.
#core#ts5#generics#interview

ConstructorParameters<T>

TypeScript 🟡 Mid

Utility type qui extrait les types des paramètrès du constructeur d'une classe sous forme de tuple.

Comme lire la notice de montage d'un meuble pour savoir quels outils sont nécessaires.

class Service {
  constructor(public url: string, public timeout: number) {}
}
type Args = ConstructorParameters<typeof Service>;
// [string, number]

Cas d'usage : Créer des factory functions ou des conteneurs d'injection de dépendances types.

#utility-types#advanced

Covariance / Contravariance

TypeScript 🔴 Senior? entretien

Covariance: un sous-type peut remplacer le type parent (sortie). Contravariance: le type parent peut remplacer le sous-type (entrée). Déterminé la compatibilité des generics.

Covariance: un chien peut passer la ou un animal est attendu (du spécifique au général). Contravariance: l'inverse pour les consommateurs.

// Covariant: retour de fonction
type Getter<T> = () => T; // Dog -> Animal OK
// Contravariant: parametre de fonction
type Setter<T> = (val: T) => void; // Animal -> Dog OK

Cas d'usage : Comprendre pourquoi certaines assignations génériques échouent et concevoir des APIs correctement typées.

#advanced#interview#type-system

Declaration Maps

TypeScript 🔴 Senior

Fichiers .d.ts.map qui lient les déclarations aux sources originales. Permettent 'Go to Définition' de naviguer vers le .ts source au lieu du .d.ts.

Comme un GPS qui mène directement a l'usine au lieu de s'arrêter a la vitrine du magasin.

// tsconfig.json
{
  "compilerOptions": {
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}

Cas d'usage : Monorepos et bibliothèques ou les développeurs doivent naviguer vers le code source des dépendances.

#tooling#monorepo

Declaration Merging

TypeScript 🔴 Senior? entretien

Mécanisme ou plusieurs déclarations du même nom sont fusionnées en une seule définition. S'applique aux interfaces, namespaces et enums.

Comme deux équipes qui construisent chacune une aile du même bâtiment — a la fin, c'est un seul édifice.

interface Box { width: number }
interface Box { height: number }
// Box = { width: number; height: number }
const b: Box = { width: 10, height: 20 };

Cas d'usage : Étendre les types de bibliothèques tierces sans modifier leur code source.

Anti-pattern : Abuser du merging pour patcher des types au lieu de créer des extensions propres — difficulté de traçabilité.
#advanced#interview

Decorator (legacy + stage 3)

TypeScript 🔴 Senior

Syntaxe @décorateur pour modifier ou annoter une classe et ses membres. TypeScript compile la version standard depuis la 5.0 (16 mars 2023) et les métadonnées (Symbol.metadata) depuis la 5.2, en plus des décorateurs historiques (experimentalDecorators). Côté TC39, la proposition Decorators figure au Stage 2.7 dans le tableau officiel au 27 septembre 2026 (dernière présentation : mai 2026) : elle n'est donc pas encore dans ECMAScript.

Comme un cadre autour d'un tableau — il enveloppe l'oeuvre sans la modifier, en ajoutant du contexte.

// Décorateur standard (TS 5.0+), sans experimentalDecorators
function log<T extends (...a: any[]) => any>(
  cible: T, ctx: ClassMethodDecoratorContext
) {
  return function (this: unknown, ...args: any[]) {
    console.log(`appel ${String(ctx.name)}`);
    return cible.apply(this, args);
  } as T;
}
class Api {
  @log salut() { return 'hi'; }
}

Cas d'usage : Programmation orientée aspect (journalisation, autorisations, validation) dans Angular, NestJS ou TypeORM. Le mot-clé accessor (TS 4.9) crée un champ décorable avec getter/setter.

Anti-pattern : Mélanger décorateurs historiques et standard dans un même projet. Compter sur les décorateurs avec le type stripping de Node.js : il ne les supporte pas (ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX).
#advanced#pattern#framework#ts5

Decorator Metadata (Symbol.metadata)

TypeScript 🔴 Senior

Depuis TypeScript 5.2, chaque décorateur standard reçoit context.metadata, un objet partagé par tous les décorateurs d'une même classe et exposé ensuite via Classe[Symbol.metadata]. Il remplace reflect-metadata pour attacher des informations (sérialisation, validation) lisibles à l'exécution. La proposition TC39 « Decorator Metadata » est au Stage 2.7 au 27 septembre 2026 ; un polyfill Symbol.metadata ??= Symbol('metadata') est requis.

Le carnet de bord agrafé au dossier de la classe, où chaque décorateur écrit sa note.

Symbol.metadata ??= Symbol('Symbol.metadata'); // polyfill

function serialisable(_: unknown, ctx: ClassFieldDecoratorContext) {
  (ctx.metadata.champs ??= [] as string[]).push(String(ctx.name));
}
class Utilisateur {
  @serialisable nom = '';
  @serialisable email = '';
  motDePasse = '';
}
Utilisateur[Symbol.metadata]!.champs; // ['nom', 'email']

Cas d'usage : ORM, validation, sérialisation sélective, injection de dépendances sans reflect-metadata.

Anti-pattern : Mélanger emitDecoratorMetadata (legacy) et Symbol.metadata : deux mécanismes incompatibles.
#advanced#ts5.2#decorators

Default Generic

TypeScript 🟡 Mid

Valeur par défaut assignée a un paramètre générique, utilisée quand le type n'est pas explicitement fourni ni inferable. Similaire aux paramètrès par défaut de fonctions.

Comme la taille standard d'un vêtement — si vous ne précisez pas, on vous donne du M.

interface ApiResponse<T = unknown> {
  data: T;
  status: number;
}
const res: ApiResponse = { data: null, status: 200 };
const typed: ApiResponse<User> = { data: user, status: 200 };

Cas d'usage : Fournir un type par défaut dans les bibliothèques pour simplifier l'usage basique tout en permettant la personalisation.

#generics#api-design

Discriminated Union

TypeScript 🟡 Mid? entretien

Union de types partageant une propriété commune (discriminant) qui permet a TS de distinguer chaque variante. Pattern fondamental pour modéliser des états.

Comme des colis avec une étiquette de couleur — la couleur suffit pour savoir quel traitement appliquer.

type Result =
  | { status: "ok"; data: string }
  | { status: "error"; message: string };
function handle(r: Result) {
  if (r.status === "ok") r.data; // string
  else r.message; // string
}

Cas d'usage : Modéliser des états applicatifs (loading/success/error) avec exhaustivité garantie par le compilateur.

Anti-pattern : Utiliser des booléens multiples (isLoading, hasError) au lieu d'une union discriminée — états impossibles deviennent possibles.
#core#interview#pattern

Distributive Conditional Types

TypeScript 🔴 Senior

Quand un type conditionnel agit sur un paramètre générique nu (T extends U), il se distribue sur chaque membre d'une union. Chaque membre est évalué indépendamment.

Comme un tri postal — chaque lettre de la pile est examinées individuellement et envoyée dans la bonne boite.

type NoNull<T> = T extends null | undefined ? never : T;
type R = NoNull<string | null | number>;
// string | number (null elimine)

Cas d'usage : Filtrer ou transformer chaque membre d'une union indépendamment (Exclude, Extract fonctionnent ainsi).

Anti-pattern : Ne pas comprendre la distribution et obtenir des résultats inattendus — utiliser [T] extends [U] pour la désactiver.
#advanced#type-system

Enum vs const Enum vs Union

TypeScript 🟡 Mid? entretien

Trois façons de modéliser un ensemble fini: enum (objet runtime), const enum (inline a la compilation, efface), union de littéraux (zéro runtime). Chacune avec ses compromis.

Enum: un panneau permanent. Const enum: un post-it qu'on retire après lecture. Union: une règle orale connue de tous.

enum Dir { Up, Down } // objet JS emis
const enum Fast { A, B } // inline, pas d'objet
type Clean = "up" | "down"; // zero runtime

Cas d'usage : Préférer les unions de littéraux pour la légèreté. Enum pour l'itération. Const enum pour la performance (avec précaution).

Anti-pattern : Utiliser des enums numériques sans valeur explicite — l'ajout d'un membre casse les valeurs persistees.
#core#interview#best-practice

Exclude<T, U>

TypeScript 🟡 Mid? entretien

Utility type qui retire d'une union T tous les membres assignables a U. Fonctionne sur les unions de types, pas sur les propriétés d'objets.

Comme un filtre a café qui retient le marc — seul le liquide (les types voulus) passe.

type AllEvents = "click" | "focus" | "blur" | "scroll";
type UIEvents = Exclude<AllEvents, "scroll">;
// "click" | "focus" | "blur"

Cas d'usage : Filtrer des unions pour créer des sous-ensembles de types (evenements, statuts, permissions).

#core#interview#utility-types

Exhaustive Check (never)

TypeScript 🟡 Mid? entretien

Technique utilisant le type never pour garantir que tous les cas d'une union sont traites. Si un cas est oublie, le compilateur génère une erreur.

Comme une checklist de sécurité en aviation — chaque point doit être coche, aucun oubli n'est toléré.

type Shape = "circle" | "square";
function area(s: Shape) {
  switch (s) {
    case "circle": return 1;
    case "square": return 2;
    default: const _: never = s; return _;
  }
}

Cas d'usage : Garantir a la compilation que tout ajout a une union est géré partout dans le code.

Anti-pattern : Mettre un default générique qui ignore les nouveaux cas — les bugs passent en silence.
#core#interview#safety

Extract<T, U>

TypeScript 🟡 Mid

Utility type qui extrait d'une union T les membres assignables a U. Inverse d'Exclude — garde uniquement les types correspondants.

Comme un aimant dans un tas de billes — il n'attrape que celles en métal.

type Mixed = string | number | boolean | null;
type Primitives = Extract<Mixed, string | number>;
// string | number

Cas d'usage : Extraire les types spécifiques d'une large union pour un traitement spécialisé.

#core#utility-types

Generic Constraint (extends)

TypeScript 🟡 Mid? entretien

Restriction appliquée a un paramètre générique via extends pour garantir qu'il possède certaines propriétés. Limite les types acceptables.

Comme un casting de film — tout le monde peut postuler, mais il faut au minimum savoir chanter.

function getLength<T extends { length: number }>(x: T) {
  return x.length;
}
getLength("hello"); // OK
getLength([1, 2]);  // OK
// getLength(42);   // Erreur: pas de length

Cas d'usage : Garantir qu'un générique possède les propriétés nécessaires avant de les utiliser.

Anti-pattern : Contraindre trop largement (extends object) ou pas assez — soit trop restrictif, soit pas assez sur.
#core#interview#generics

Generic Function

TypeScript 🟡 Mid? entretien

Fonction paramétrée par un ou plusieurs types qui sont résolus a l'appel. Permet d'écrire du code réutilisable tout en conservant la sécurité des types.

Comme un moule a gâteau adaptable — même forme de base mais le résultat s'adapte a l'ingrédient (chocolat, vanille).

function first<T>(arr: T[]): T | undefined {
  return arr[0];
}
const n = first([1, 2, 3]); // number
const s = first(["a", "b"]); // string

Cas d'usage : Créer des fonctions utilitaires (map, filter, fetch wrapper) qui préservent les types d'entrée/sortie.

Anti-pattern : Utiliser any au lieu de generics — on perd complètement la sécurité de type en sortie.
#core#interview#generics

Generic Inference

TypeScript 🟡 Mid

Capacité de TS a déduire automatiquement les paramètrès génériques a partir des arguments passes. Évite de spécifier explicitement les types a chaque appel.

Comme un traducteur qui détecte automatiquement la langue source sans qu'on lui dise.

function wrap<T>(value: T): { value: T } {
  return { value };
}
const r = wrap(42); // T infere comme number
const s = wrap("hi"); // T infere comme string

Cas d'usage : Concevoir des APIs génériques ergonomiques ou l'utilisateur n'a pas a spécifier les types manuellement.

#generics#core

Global Augmentation

TypeScript 🔴 Senior

Technique pour ajouter des déclarations au scope global via déclaré global dans un module. Permet d'étendre Window, globalThis ou les prototypes.

Comme un décret national qui ajoute une loi applicable partout — la modification est globale.

export {};
declare global {
  interface Window {
    analytics: { track(e: string): void };
  }
}

Cas d'usage : Déclarer des variables globales injectées (analytics, config, feature flags) avec un typage correct.

Anti-pattern : Polluer le scope global au lieu d'utiliser des imports — retour aux problèmes pre-modules.
#advanced#tooling

Incremental Compilation

TypeScript 🟡 Mid

Option (incremental: true) qui sauvegarde un cache (.tsbuildinfo) pour ne recompiler que les fichiers modifies. Accélère drastiquement les rebuilds.

Comme un cuisinier qui ne recoupe que les légumes manquants au lieu de tout reprendre a zéro.

// tsconfig.json
{
  "compilerOptions": {
    "incremental": true,
    "tsBuildInfoFile": "./.tsbuildinfo"
  }
}

Cas d'usage : Tout projet de taille moyenne+ devrait activer l'incremental pour des temps de build réduits.

#tooling#performance

Inferred Type Predicates

TypeScript 🟡 Mid? entretien

Depuis TypeScript 5.5 (20 juin 2024), le compilateur infère lui-même le prédicat de type (x is T) d'une fonction dont le corps se réduit à une vérification de type sur son paramètre. Le cas emblématique : arr.filter(x => x !== undefined) renvoie désormais T[] et non (T | undefined)[], sans annotation manuelle.

Le videur qui, en vous voyant sortir la carte d'identité, comprend tout seul ce qu'il vérifie.

const valeurs: (number | undefined)[] = [1, undefined, 3];

// TS 5.5 : inféré comme (x) => x is number
const nombres = valeurs.filter(x => x !== undefined);
nombres.map(n => n.toFixed(1)); // n: number, plus d'erreur

// Fonction nommée : signature inférée `pet is Fish`
function estPoisson(p: Fish | Bird) {
  return 'swim' in p;
}

Cas d'usage : Filtrage de tableaux, nettoyage de valeurs nulles, découpage d'unions sans écrire de type guard explicite.

Anti-pattern : Continuer à écrire des prédicats manuels partout : ils masquent l'inférence et risquent d'être faux (le compilateur les croit).
#core#ts5.5#interview

InstanceType<T>

TypeScript 🟡 Mid

Utility type qui extrait le type d'instance d'un constructeur de classe. Utile quand on travaille avec typeof Class.

Comme connaître le plat final en voyant la recette — le constructeur est la recette, l'instance est le plat.

class Logger { log(msg: string) {} }
type LoggerInstance = InstanceType<typeof Logger>;
function inject(cls: typeof Logger): LoggerInstance {
  return new cls();
}

Cas d'usage : Typer des instances dans des systèmes d'injection de dépendances ou factories génériques.

#utility-types

isolatedModules

TypeScript 🟡 Mid

Option tsconfig qui garantit que chaque fichier peut être transpilé isolément, sans analyse inter-fichiers (compatible Babel, esbuild, SWC, Oxc). Elle interdit par exemple le ré-export d'un type sans le mot-clé type. Son complément récent est --erasableSyntaxOnly (TS 5.8, 28 février 2025), qui bannit la syntaxe non effaçable (enum, namespace avec code, propriétés de paramètre) pour le type stripping natif de Node.js.

Comme une règle qui dit que chaque chapitre d'un livre doit être compréhensible seul, sans lire les autres.

// tsconfig.json
{ "compilerOptions": { "isolatedModules": true } }
// Interdit: export { Type } from "./types"
// OK: export type { Type } from "./types"

Cas d'usage : Obligatoire dès qu'un transpileur non-TS produit le JavaScript : Vite 8 (Oxc), esbuild, SWC, ou Node.js exécutant directement un fichier .ts.

Anti-pattern : Désactiver isolatedModules avec esbuild/Vite — des re-exports de types cassent silencieusement le build.
#tooling#best-practice#ts5

Key Remapping (as)

TypeScript 🔴 Senior

Possibilité dans un mapped type de renommer les clés via la clause as. Permet de filtrer, transformer ou préfixer les clés d'un type.

Comme un rebranding — même produit, mais chaque nom est transforme selon une nouvelle convention.

type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
type UserGetters = Getters<{ name: string }>;
// { getName: () => string }

Cas d'usage : Générer automatiquement des noms de getters/setters ou filtrer des clés par type.

#advanced#type-system

Literal Types

TypeScript 🟢 Junior? entretien

Types qui représentent une valeur exacte plutôt qu'une catégorie. Permet de restreindre une variable a des valeurs précises comme "GET" | "POST".

Comme un menu fixe au restaurant — vous ne pouvez choisir que parmi les plats proposes, pas inventer le votre.

type Method = "GET" | "POST" | "PUT";
const req = (method: Method) => fetch("/", { method });
req("GET");  // OK
// req("PATCH"); // Erreur

Cas d'usage : Restreindre les paramètrès de configuration aux seules valeurs valides.

Anti-pattern : Utiliser string la ou un ensemble fini de valeurs est attendu — aucune aide de l'autocompletion.
#core#interview#beginner

Mapped Types

TypeScript 🟡 Mid? entretien

Types qui transforment chaque propriété d'un type existant via une itération sur ses clés. Base de Partial, Required, Readonly et autres utility types.

Comme une chaîne de montage qui applique la même transformation a chaque pièce — chaque propriété passe par le même moule.

type Optional<T> = {
  [K in keyof T]?: T[K];
};
interface User { name: string; age: number }
type PartialUser = Optional<User>;
// { name?: string; age?: number }

Cas d'usage : Créer des variantes de types existants (formulaires partiels, versions readonly, DTOs).

Anti-pattern : Redéfinir manuellement chaque variante d'un type au lieu d'utiliser un mapped type — duplication et desynchronisation.
#core#interview#type-system

Module Augmentation

TypeScript 🔴 Senior

Technique pour ajouter des déclarations a un module existant via déclaré module. Permet d'étendre les types d'une lib tierce.

Comme ajouter une extension a une maison existante — la structure originale reste intacte mais gagne de nouvelles pièces.

// Etendre express
declare module "express" {
  interface Request {
    userId?: string;
  }
}

Cas d'usage : Ajouter des propriétés typées aux objets de frameworks (Request express, Session, Window).

Anti-pattern : Augmenter des modules sans documenter pourquoi — les futurs développeurs ne comprennent pas d'ou viennent les types.
#advanced#tooling

NoInfer<T>

TypeScript 🟡 Mid

Type utilitaire intrinsèque ajouté en TypeScript 5.4 (6 mars 2024). Envelopper un paramètre dans NoInfer<T> l'exclut des candidats à l'inférence de T : le type générique est alors déduit uniquement des autres arguments, et l'argument marqué est simplement vérifié contre lui.

Dans un jury, le témoin qui n'a pas le droit de vote mais doit quand même respecter le verdict.

function feu<C extends string>(couleurs: C[], defaut?: NoInfer<C>) {}

feu(['rouge', 'vert'], 'rouge'); // OK
feu(['rouge', 'vert'], 'bleu');
// ❌ 'bleu' n'est pas assignable à 'rouge' | 'vert'
// Sans NoInfer, C serait inféré 'rouge' | 'vert' | 'bleu' : pas d'erreur

Cas d'usage : Fonctions où un argument « valeur par défaut » ou « clé » doit appartenir à un ensemble déduit d'un autre argument.

Anti-pattern : Simuler NoInfer avec des astuces du type C & {} ou des tuples : moins lisible et fragile entre versions.
#core#ts5.4#generics

NonNullable<T>

TypeScript 🟢 Junior

Utility type qui retire null et undefined d'une union. Garantit qu'une valeur existe réellement.

Comme un contrôle qualité qui rejette les boites vides — seuls les produits réels passent.

type Maybe = string | null | undefined;
type Sure = NonNullable<Maybe>; // string

Cas d'usage : Nettoyer les types après une vérification de nullité pour travailler avec des valeurs garanties.

#core#utility-types

Omit<T, K>

TypeScript 🟢 Junior? entretien

Utility type qui crée un nouveau type en excluant certaines propriétés. Inverse de Pick — on retire au lieu de sélectionner.

Comme un menu sans allergenes — on retire les ingrédients problématiques et on garde le reste.

interface User { id: string; name: string; password: string }
type SafeUser = Omit<User, "password">;
// { id: string; name: string }

Cas d'usage : Exclure des champs sensibles (password, token) des types de réponse API.

#core#interview#utility-types

OmitThisParameter<T>

TypeScript 🔴 Senior

Utility type qui retire le paramètre this d'une signature de fonction. Produit une fonction callable sans contexte spécifique.

Comme détacher un badge nominatif d'un uniforme — la fonction devient anonyme et utilisable par tous.

function greet(this: { name: string }) {
  return this.name;
}
type Plain = OmitThisParameter<typeof greet>;
// () => string
const fn: Plain = greet.bind({ name: "A" });

Cas d'usage : Exposer des méthodes liées (bound) qui n'ont plus besoin de contexte this explicite.

#advanced#utility-types

Opaque Types

TypeScript 🔴 Senior

Types dont la structure interne est masquée aux consommateurs. Seul le module créateur peut construire et inspecter la valeur. Variante plus stricte des branded types.

Comme une boite noire scellée — on sait ce qu'elle représente mais seul le fabricant peut l'ouvrir.

declare const __opaque: unique symbol;
type Opaque<T, K> = T & { [__opaque]: K };
type Token = Opaque<string, "Token">;
const createToken = (s: string): Token => s as Token;

Cas d'usage : Encapsuler des tokens, identifiants ou valeurs validées pour empêcher la manipulation directe.

#advanced#pattern#safety

Overload Signatures

TypeScript 🟡 Mid? entretien

Plusieurs signatures de fonction déclarées avant l'implémentation pour décrire différentes combinaisons d'arguments/retours. L'implémentation doit être compatible avec toutes.

Comme un restaurant avec différents menus selon le nombre de convives — même cuisine, mais offres distinctes.

function parse(input: string): number;
function parse(input: number): string;
function parse(input: string | number) {
  return typeof input === "string"
    ? parseInt(input) : input.toString();
}

Cas d'usage : APIs avec des relations précises entre types d'entrée et de sortie (createElement, addEventListener).

Anti-pattern : Utiliser des overloads quand une simple union ou un generic suffirait — complexité inutile.
#core#interview#api-design

Parameters<T>

TypeScript 🟡 Mid

Utility type qui extrait les types des paramètrès d'une fonction sous forme de tuple. Permet de réutiliser la signature d'une fonction.

Comme photographier les ingrédients d'un chef pour reproduire sa recette exactement.

function greet(name: string, age: number) {}
type Args = Parameters<typeof greet>;
// [string, number]
const args: Args = ["Alice", 30];

Cas d'usage : Wrapper des fonctions existantes ou créer des décorateurs qui préservent la signature.

#core#utility-types

Partial<T>

TypeScript 🟢 Junior? entretien

Utility type qui rend toutes les propriétés d'un type optionnelles. Équivalent a ajouter ? a chaque propriété.

Comme un formulaire ou aucun champ n'est obligatoire — remplissez ce que vous voulez.

interface User { name: string; age: number }
function update(id: string, data: Partial<User>) {
  // data.name et data.age sont optionnels
}
update("1", { name: "Alice" }); // OK

Cas d'usage : Fonctions de mise a jour partielle (PATCH) ou options de configuration avec des valeurs par défaut.

Anti-pattern : Utiliser Partial partout et perdre la garantie que les champs requis sont présents a la création.
#core#interview#utility-types

Phantom Types

TypeScript 🔴 Senior

Types parametriques dont le paramètre générique n'est pas utilise dans la structure mais sert de marqueur compile-time. Ajoutent de l'information de type sans coût runtime.

Comme un tampon invisible sur un billet — l'oeil nu ne le voit pas mais le scanner le détecte.

type Validated = { __validated: true };
type Raw = { __raw: true };
type Email<T> = string & { __phantom: T };
function validate(e: Email<Raw>): Email<Validated> {
  if (!e.includes("@")) throw Error("Invalid");
  return e as Email<Validated>;
}

Cas d'usage : Marquer les étapes de validation (raw -> sanitized -> validated) au niveau du système de types.

#advanced#pattern#safety

Pick<T, K>

TypeScript 🟢 Junior? entretien

Utility type qui extrait un sous-ensemble de propriétés d'un type existant. Créé un nouveau type avec seulement les clés spécifiées.

Comme choisir des ingrédients dans un buffet — on ne prend que ce dont on a besoin.

interface User { id: string; name: string; email: string }
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string }

Cas d'usage : Créer des DTOs légers pour les listes ou les réponses API partielles.

#core#interview#utility-types

Project References

TypeScript 🔴 Senior

Système permettant de décomposer un gros projet en sous-projets TS avec des dépendances explicites. Chaque sous-projet se compile indépendamment.

Comme un immeuble modulaire — chaque étage est construit séparément puis assemble.

// tsconfig.json
{
  "references": [
    { "path": "./packages/core" },
    { "path": "./packages/api" }
  ]
}
// Build: tsc --build

Cas d'usage : Monorepos et gros projets ou la compilation complète est trop lente — chaque module compile isolement.

#tooling#performance#monorepo

Readonly<T>

TypeScript 🟢 Junior? entretien

Utility type qui rend toutes les propriétés en lecture seule. Toute tentative de mutation génère une erreur a la compilation.

Comme un document sous verre dans un musée — on peut le regarder mais pas le toucher.

interface State { count: number; name: string }
const state: Readonly<State> = { count: 0, name: "A" };
// state.count = 1; // Erreur: readonly

Cas d'usage : Protéger l'état dans Redux/stores immutables ou les paramètrès de fonctions pures.

Anti-pattern : Oublier que Readonly est superficiel — les objets imbriques restent mutables.
#core#interview#utility-types

Record<K, V>

TypeScript 🟢 Junior? entretien

Utility type qui construit un type objet dont les clés sont de type K et les valeurs de type V. Alternative typée aux objets indexe.

Comme un tableau Excel avec des colonnes prédéfinies — chaque ligne a exactement les mêmes champs.

type Role = "admin" | "user" | "guest";
const permissions: Record<Role, string[]> = {
  admin: ["read", "write", "delete"],
  user: ["read", "write"],
  guest: ["read"]
};

Cas d'usage : Créer des dictionnaires/maps types pour des lookups, configurations par clé ou traductions.

Anti-pattern : Utiliser { [key: string]: any } au lieu de Record avec des clés précises — perte d'autocompletion.
#core#interview#utility-types

Recursive Conditional Types

TypeScript 🔴 Senior

Types conditionnels qui se referencent eux-mêmes pour traiter des structures de profondeur variable. Permettent des transformations profondes sur les types.

Comme une équipe de nettoyage qui descend étage par étage dans un immeuble — chaque niveau est traite avant de passer au suivant.

type DeepReadonly<T> = T extends object
  ? { readonly [K in keyof T]: DeepReadonly<T[K]> }
  : T;
type Nested = { a: { b: { c: string } } };
type R = DeepReadonly<Nested>;

Cas d'usage : Créer des transformations profondes (DeepPartial, DeepReadonly, flatten) sur des structures imbriquées.

Anti-pattern : Récursion trop profonde sans limite — TS a une profondeur max (~50) et génère des erreurs cryptiques.
#advanced#type-system

Recursive Types

TypeScript 🔴 Senior

Types qui se referencent eux-mêmes, permettant de modéliser des structures arborescentes ou imbriquées comme du JSON, un DOM ou un système de fichiers.

Comme des poupées russes — chaque poupée contient potentiellement une autre poupée identique.

type Json =
  | string
  | number
  | boolean
  | null
  | Json[]
  | { [key: string]: Json };

Cas d'usage : Modéliser des structures de données naturellement recursives (arbres, JSON, menus imbriques).

Anti-pattern : Créer des récursions infinies sans condition d'arrêt — le compilateur plante ou devient très lent.
#advanced#type-system

Required<T>

TypeScript 🟢 Junior

Utility type qui rend toutes les propriétés obligatoires. Inverse de Partial — supprime tous les modificateurs optionnels (?).

Comme un formulaire administratif ou chaque champ est marque d'un astérisque rouge — tout est obligatoire.

interface Config {
  host?: string;
  port?: number;
}
type FullConfig = Required<Config>;
// { host: string; port: number }

Cas d'usage : Garantir qu'un objet de configuration est complet après la fusion avec les valeurs par défaut.

#core#utility-types

ReturnType<T>

TypeScript 🟡 Mid? entretien

Utility type qui extrait le type de retour d'une fonction. Utile pour inférer des types sans les redeclarer.

Comme lire l'étiquette de sortie d'une machine sans devoir regarder ses rouages internes.

function createUser() {
  return { id: "1", name: "Alice", active: true };
}
type User = ReturnType<typeof createUser>;
// { id: string; name: string; active: boolean }

Cas d'usage : Inférer le type de retour de fonctions factory ou de hooks React sans duplication.

Anti-pattern : Déclarer manuellement un type qui duplique le retour d'une fonction — desynchronisation garantie.
#core#interview#utility-types

satisfies operator

TypeScript 🟡 Mid? entretien

Opérateur introduit en TypeScript 4.9 qui vérifie qu'une valeur est conforme à un type sans élargir le type inféré. On garde la validation (clés manquantes, fautes de frappe) et la précision des littéraux pour l'autocomplétion.

Comme un contrôle qualité qui valide la conformité sans changer l'étiquette du produit.

type Colors = Record<string, [number, number, number]>;
const palette = {
  red: [255, 0, 0],
  green: [0, 255, 0],
} satisfies Colors;
palette.red; // type [number, number, number], pas Colors

Cas d'usage : Valider une configuration tout en gardant l'autocompletion sur les clés et valeurs exactes.

Anti-pattern : Utiliser un type annotation qui élargit le type et perd l'autocompletion sur les clés spécifiques.
#core#interview#ts4.9

Strict Mode Flags

TypeScript 🟡 Mid

Ensemble d'options (strictNullChecks, noImplicitAny, strictFunctionTypes, strictBindCallApply, etc.) activées d'un coup par strict. Depuis TypeScript 6.0 (23 mars 2026), strict vaut true par défaut : un projet sans tsconfig ou sans l'option est strict, et il faut écrire strict: false pour revenir en arrière.

Comme passer le contrôle technique en mode strict — plus de vérifications mais véhicule plus fiable.

// tsconfig.json
{
  "compilerOptions": {
    "strict": true
    // Active: strictNullChecks, noImplicitAny,
    // strictBindCallApply, strictFunctionTypes...
  }
}

Cas d'usage : Toujours activer strict en début de projet pour maximiser la sécurité du typage des le départ.

Anti-pattern : Désactiver strict pour faire compiler du code existant : la dette est repoussée et multipliée. Depuis TS 6.0, alwaysStrict: false est également déprécié.
#core#best-practice#tooling

Structural Typing

TypeScript 🟡 Mid? entretien

Système de typage ou la compatibilité est basée sur la structure (propriétés/méthodes) et non sur le nom du type. Deux types avec la même forme sont compatibles.

Comme un recruteur qui juge sur les compétences réelles plutôt que sur le diplôme — si tu sais faire le job, tu es accepte.

interface Point { x: number; y: number }
const p = { x: 1, y: 2, z: 3 };
const accept = (pt: Point) => pt.x;
accept(p); // OK: p a x et y

Cas d'usage : Permet l'interopérabilité entre modules sans couplage fort sur les noms de types.

Anti-pattern : Supposer que deux types avec le même nom sont identiques — c'est la structure qui compte, pas le nom.
#core#interview#type-system

Template Literal Parsing

TypeScript 🔴 Senior

Technique de parsing de chaînés au niveau des types via template literals et infer. Permet d'extraire des parties de routes, selectors CSS ou patterns.

Comme un scanner qui lit un code-barres et en extrait chaque segment d'information automatiquement.

type ParseRoute<T> = T extends `/${infer Seg}/${infer Rest}`
  ? Seg | ParseRoute<`/${Rest}`>
  : T extends `/${infer Last}` ? Last : never;
type R = ParseRoute<"/users/123/posts">;
// "users" | "123" | "posts"

Cas d'usage : Extraire des paramètrès de route, parser des DSL ou valider des formats de chaînés a la compilation.

#advanced#pattern#type-system

Template Literal Types

TypeScript 🔴 Senior? entretien

Types construits via des template strings qui combinent des types littéraux. Permettent de générer dynamiquement des types a partir de patterns de chaînés.

Comme un générateur de noms compose — prénom + nom donne toutes les combinaisons possibles automatiquement.

type Event = "click" | "focus";
type Handler = `on${Capitalize<Event>}`;
// "onClick" | "onFocus"
type Locale = `${"en" | "fr"}-${"US" | "FR"}`;
// "en-US" | "en-FR" | "fr-US" | "fr-FR"

Cas d'usage : Typer des clés CSS, des routes API ou des noms d'evenements générés dynamiquement.

Anti-pattern : Générer des unions trop larges avec des template literals — explosion combinatoire qui ralentit le compilateur.
#advanced#interview#type-system

ThisParameterType<T>

TypeScript 🔴 Senior

Utility type qui extrait le type du paramètre this d'une fonction. Retourne unknown si pas de paramètre this explicite.

Comme identifier le propriétaire d'un outil en regardant l'étiquette sur la poignée.

function greet(this: { name: string }) {
  return `Hello ${this.name}`;
}
type Ctx = ThisParameterType<typeof greet>;
// { name: string }

Cas d'usage : Extraire le contexte this pour le réutiliser dans des décorateurs ou des wrappers de méthodes.

#advanced#utility-types

Triple-Slash Directives

TypeScript 🔴 Senior

Instructions spéciales en commentaire (/// <référence ...>) en haut des fichiers pour inclure des types ou des fichiers de déclaration. Usage rare avec les modules modernes.

Comme une note en marge d'un manuscrit qui dit 'voir aussi le chapitre X' — une référence croisée.

/// <reference types="node" />
/// <reference path="./legacy.d.ts" />
// Charge les types node et le fichier legacy

Cas d'usage : Inclure des types globaux (DOM, Node) ou référencer des fichiers .d.ts dans des projets sans bundler.

Anti-pattern : Utiliser des triple-slash au lieu d'imports ES modules — méthode obsolète dans les projets modernes.
#tooling#legacy

ts-expect-error vs ts-ignore

TypeScript 🟡 Mid

@ts-expect-error supprime l'erreur suivante mais échoue si aucune erreur n'existe. @ts-ignore supprime silencieusement toute erreur. Préférer expect-error.

ts-expect-error: un parapluie qu'on range s'il ne pleut pas. ts-ignore: un mur anti-bruit permanent, même en silence.

// @ts-expect-error: test avec mauvais type intentionnel
const result = fn("wrong");

// @ts-ignore: supprime toute erreur (dangereux)
const risky = badCode();

Cas d'usage : Tests ou le but est de vérifier le comportement avec des types invalides — expect-error est préférable.

Anti-pattern : Utiliser ts-ignore pour faire compiler du code — masque les vrais bugs et empêche la détection de régressions.
#best-practice#tooling

tsconfig.json

TypeScript 🟢 Junior

Fichier de configuration central d'un projet TypeScript : options du compilateur, fichiers inclus, résolution des modules. Depuis TypeScript 6.0 (23 mars 2026), les valeurs par défaut ont changé : strict à true, module à esnext, target à es2025, types à [] et rootDir au dossier du tsconfig. TypeScript 7.0 (8 juillet 2026) supprime target es5, baseUrl, moduleResolution classic/node10 et les modules amd/umd/systemjs.

Comme le tableau de bord d'une voiture — tous les réglages du moteur TypeScript en un seul endroit.

{
  "compilerOptions": {
    "target": "es2025",
    "module": "nodenext",
    "strict": true,
    "types": ["node"],
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "outDir": "dist"
  },
  "include": ["src"]
}

Cas d'usage : Tout projet TypeScript commence par un tsconfig. Depuis 5.9, tsc --init génère un fichier minimal et prescriptif plutôt qu'un gabarit exhaustif commenté.

Anti-pattern : Copier un tsconfig d'avant la 6.0 sans relire les options : baseUrl est déprécié et types n'inclut plus tous les @types (ajouter "types": ["node"] pour un projet Node).
#core#tooling#beginner#ts6#ts7

TSDoc

TypeScript 🟢 Junior

Standard de documentation pour TypeScript base sur JSDoc avec des tags normalises (@param, @returns, @example). Supporte par les IDEs et générateurs de docs.

Comme les notices d'utilisation standardisées — même format partout pour une compréhension universelle.

/**
 * Calcule la TVA d'un montant.
 * @param amount - Le montant HT
 * @param rate - Le taux (defaut 0.2)
 * @returns Le montant TTC
 */
function withTax(amount: number, rate = 0.2) {}

Cas d'usage : Documenter les APIs publiques pour que les IDEs affichent l'aide contextuelle et générer la doc.

Anti-pattern : Documenter chaque ligne triviale — le code devrait être auto-explicatif, les docs pour les cas complexes.
#tooling#best-practice#beginner

Type Guard

TypeScript 🟡 Mid? entretien

Expression qui affine le type dans une branche conditionnelle. Inclut typeof, instanceof, in et les prédicats de type personnalises (is).

Comme un vigile a l'entrée qui vérifie votre badge — une fois passe, on sait exactement qui vous êtes.

function isString(val: unknown): val is string {
  return typeof val === "string";
}
if (isString(input)) {
  input.toUpperCase(); // type string garanti
}

Cas d'usage : Créer des gardes personnalises pour valider des données externes (API, formulaires) avec typage garanti.

Anti-pattern : Écrire un type guard qui ne vérifie pas réellement le type — le compilateur fait confiance au prédicat.
#core#interview#safety

Type Inference

TypeScript 🟢 Junior? entretien

Capacité de TypeScript a déduire automatiquement le type d'une variable a partir de sa valeur. Évite de déclarer explicitement chaque type.

Comme un serveur qui devine que vous voulez de l'eau en voyant votre verre vide, sans que vous le demandiez.

const name = "Alice"; // string infere
const nums = [1, 2, 3]; // number[] infere
const double = (x: number) => x * 2; // retour number infere

Cas d'usage : Laisser TS inférer les types évidents pour garder le code concis sans perdre la sécurité.

Anti-pattern : Annoter explicitement chaque variable triviale (const x: number = 5) alourdit le code inutilement.
#core#interview#beginner

Type Narrowing

TypeScript 🟢 Junior? entretien

Processus de réduction d'un type large vers un type plus spécifique via des conditions. TS analyse le flux de contrôle pour affiner les types.

Comme un entonnoir qui filtre progressivement — on part d'un grand ensemble pour arriver a un élément précis.

function show(val: string | number) {
  if (typeof val === "string") {
    console.log(val.toUpperCase()); // string
  } else {
    console.log(val.toFixed(2)); // number
  }
}

Cas d'usage : Manipuler des union types en toute sécurité dans les branches conditionnelles.

Anti-pattern : Utiliser des cast (as) au lieu de narrowing propre — on perd la vérification du compilateur.
#core#interview#type-system

Type Predicate

TypeScript 🟡 Mid? entretien

Annotation de retour de fonction (param is Type) qui indique au compilateur qu'un narrowing a lieu. Permet de créer des type guards personnalises.

Comme un certificat d'authenticité — la fonction garantit l'identité du type en sortie.

interface Fish { swim(): void }
interface Bird { fly(): void }
function isFish(pet: Fish | Bird): pet is Fish {
  return (pet as Fish).swim !== undefined;
}

Cas d'usage : Valider des données complexes (API responses, events) avec un typage garanti après la vérification.

Anti-pattern : Écrire un prédicat incorrect (retourne true mais le type est faux) — le compilateur fait confiance aveugle.
#core#interview#safety

Type Widening

TypeScript 🟡 Mid? entretien

Mécanisme ou TS élargit automatiquement un type littéral vers un type plus général. Une variable let initialisée a "hello" devient string, pas "hello".

Comme un cadre photo extensible qui s'adapte a toutes les tailles au lieu de rester fixe sur une seule dimension.

let x = "hello"; // type: string (widened)
const y = "hello"; // type: "hello" (literal)
let z: "hello" = "hello"; // type: "hello" (explicite)

Cas d'usage : Comprendre le widening pour éviter les erreurs avec les types littéraux dans les fonctions.

Anti-pattern : Utiliser let partout et perdre les types littéraux nécessaires pour les discriminated unions.
#core#interview#type-system

Type-level Programming

TypeScript 🔴 Senior

Technique avancée consistant a écrire de la logique (conditions, boucles, pattern matching) entièrement dans le système de types TS, sans code runtime.

Comme résoudre des équations sur un tableau blanc — tout se passe dans la théorie, rien n'est exécuté.

type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>;      // false
type Length<T extends any[]> =
  T extends { length: infer L } ? L : never;

Cas d'usage : Créer des validations de types complexes dans les bibliothèques (zod, tRPC, Prisma).

Anti-pattern : Écrire du type-level programming complexe pour des cas simples — maintenance cauchemardesque.
#advanced#type-system

Type-safe Event Emitter

TypeScript 🔴 Senior

Pattern d'event emitter ou les noms d'evenements et leurs payloads sont types statiquement. Garantit la correspondance émit/on a la compilation.

Comme un standard téléphonique type — chaque extension a un format de message prédéfini, pas de mauvaise connexion.

type Events = { login: { userId: string }; logout: void };
class Emitter<T extends Record<string, any>> {
  on<K extends keyof T>(event: K, fn: (data: T[K]) => void) {}
  emit<K extends keyof T>(event: K, data: T[K]) {}
}
const bus = new Emitter<Events>();

Cas d'usage : Systèmes event-driven (WebSocket, pub/sub, bus d'evenements) avec garantie de type sur les payloads.

#advanced#pattern#real-world

TypeScript 6.0 (version pont)

TypeScript 🟡 Mid

TypeScript 6.0 (23 mars 2026) est la dernière version écrite en JavaScript et fait le pont vers la 7.0 native. Elle change les défauts (strict: true, module: esnext, target: es2025, types: [], rootDir au dossier du tsconfig), supprime outFile, target es5, moduleResolution classic et les modules amd/umd/systemjs, et déprécie baseUrl, node10 et les import assertions (assert → with). Ses types ajoutent Temporal, RegExp.escape et les méthodes getOrInsert.

La dernière station avant le changement de ligne : on y met ses bagages en ordre.

{
  "compilerOptions": {
    "ignoreDeprecations": "6.0",
    "types": ["node"],
    "paths": { "#/*": ["./src/*"] },
    "strict": true
  }
}

Cas d'usage : Préparer une base de code à TypeScript 7 : corriger les dépréciations en 6.0, où elles sont encore des avertissements contournables.

Anti-pattern : Sauter directement de 5.x à 7.0 sans passer par 6.0 : les options supprimées deviennent des erreurs dures sans diagnostic de transition.
#core#ts6#migration

TypeScript 7 natif (tsgo / Corsa)

TypeScript 🔴 Senior

TypeScript 7.0 (8 juillet 2026) est la réécriture du compilateur en Go, nom de code « Project Corsa », publiée d'abord en aperçu sous @typescript/native-preview (binaire tsgo). Le paquet typescript 7.x fournit un tsc natif multithread annoncé 8 à 12 fois plus rapide sur un build complet (VS Code : 125,7 s → 10,6 s) avec 6 à 26 % de mémoire en moins, et un serveur de langage LSP. Il reste compatible avec le comportement de vérification de TS 6.0 ; @typescript/typescript6 permet de garder l'ancienne API JavaScript côte à côte.

Le même chef, la même recette, mais une cuisine professionnelle avec dix fourneaux au lieu d'une plaque.

# Aperçu natif (avant 7.0)
npm i -D @typescript/native-preview
npx tsgo --project tsconfig.json

# TypeScript 7 : tsc est natif
npm i -D typescript@7
npx tsc -p .

# Outils qui ont besoin de l'ancienne API JS
npm i -D @typescript/typescript6@npm:typescript@6

Cas d'usage : Monorepos et CI lentes ; éditeurs sur grosses bases ; linters typés (Oxlint s'appuie sur tsgo).

Anti-pattern : Supposer que les plugins Vue, Angular, Astro ou Svelte fonctionnent à l'identique : l'annonce 7.0 reporte leur API stable à la 7.1.
#tooling#ts7#performance#go

unknown vs any vs never vs void

TypeScript 🟡 Mid? entretien

Quatre types spéciaux: any désactivé le typage, unknown force la vérification avant usage, never représente l'impossible, void l'absence de retour.

any: joker sans règles. unknown: colis suspect a inspecter. never: porte murée. void: accusé de réception sans contenu.

function fail(): never { throw new Error(); }
function log(): void { console.log("ok"); }
function parse(x: unknown) {
  if (typeof x === "string") x.trim(); // OK
}

Cas d'usage : Utiliser unknown pour les données externes (API), void pour les callbacks, never pour l'exhaustivité.

Anti-pattern : Utiliser any pour 'faire compiler' — masque les bugs au lieu de les prévenir.
#core#interview#safety

Utility types integres qui transforment les types littéraux de chaînés. Uppercase met en majuscules, Lowercase en minuscules, Capitalize la première lettre.

Comme les boutons de mise en forme dans un traitement de texte, mais appliques directement aux types.

type A = Uppercase<"hello">;     // "HELLO"
type B = Lowercase<"HELLO">;     // "hello"
type C = Capitalize<"hello">;    // "Hello"
type D = Uncapitalize<"Hello">; // "hello"

Cas d'usage : Transformer des clés de types dans des mapped types ou template literals (getters, event handlers).

#utility-types#type-system

Variadic Tuple Types

TypeScript 🔴 Senior

Extension des tuples permettant d'utiliser des spreads génériques (...T) dans les types tuple. Permet de composer et manipuler des tuples de longueur variable.

Comme des wagons de train modulaires — on peut insérer, retirer ou combiner des sections librement.

type Concat<A extends any[], B extends any[]> = [...A, ...B];
type R = Concat<[1, 2], [3, 4]>; // [1, 2, 3, 4]
function head<T, U extends any[]>(arr: [T, ...U]): T {
  return arr[0];
}

Cas d'usage : Typer des fonctions avec des arguments variadiques (pipe, compose, curry) de manière précise.

#advanced#type-system

Variance Annotations (in/out)

TypeScript 🔴 Senior

Annotations explicites sur les paramètrès génériques pour déclarer la covariance (out), la contravariance (in) ou l'invariance. Ajoutées en TS 4.7.

Comme des panneaux 'entrée' et 'sortie' sur un parking — ils précisent dans quel sens circule le type.

interface Producer<out T> { get(): T }
interface Consumer<in T> { accept(val: T): void }
// Producer<Dog> assignable a Producer<Animal>
// Consumer<Animal> assignable a Consumer<Dog>

Cas d'usage : Documenter et vérifier la variance des types génériques dans les APIs de bibliothèques complexes.

#advanced#type-system