5 astuces TypeScript que vous ne connaissez pas
1. L'opérateur satisfies
C'est probablement l'ajout le plus utile de ces dernières versions de TypeScript, et pourtant très peu de développeurs l'utilisent. Le problème qu'il résout : comment vérifier qu'un objet respecte un type, sans perdre la précision de ses valeurs littérales ?
Sans satisfies, tu dois choisir entre deux mauvaises options :
// Option 1 : annotation directe → tu perds l'autocomplétion précise
const config: Record<string, string> = {
primary: "#B337F7",
secondary: "#111E5F",
};
// config.primary est typé "string", pas "#B337F7"
// Option 2 : pas d'annotation → aucune vérification de type
const config2 = {
primary: "#B337F7",
secndary: "#111E5F", // faute de frappe non détectée !
};
Avec satisfies, tu obtiens les deux avantages en même temps :
type ColorPalette = Record<"primary" | "secondary", string>;
const config = {
primary: "#B337F7",
secondary: "#111E5F",
} satisfies ColorPalette;
// TypeScript vérifie la conformité au type ColorPalette
// ET conserve le type précis : config.primary reste "#B337F7", pas juste "string"
Utile pour tes fichiers constant/Data.tsx : tu peux typer satisfies Project[] sur ton tableau projects pour vérifier la structure, tout en gardant l'autocomplétion exacte sur chaque slug.
2. as const pour figer les types
Par défaut, TypeScript élargit ("widen") les types littéraux vers leur type général. "Design" devient string, 42 devient number. Le suffixe as const empêche cet élargissement.
// Sans as const
const status = "loading";
// type: string (élargi)
// Avec as const
const status2 = "loading" as const;
// type: "loading" (littéral exact, figé)
C'est particulièrement puissant sur des tableaux et objets entiers :
const categories = ["Design", "Code", "Figma", "Illustrator"] as const;
// type: readonly ["Design", "Code", "Figma", "Illustrator"]
// et non pas string[]
type Category = (typeof categories)[number];
// type: "Design" | "Code" | "Figma" | "Illustrator"
Cette dernière ligne est le vrai gain : tu génères une union de types littéraux directement depuis un tableau de valeurs, sans dupliquer la liste ailleurs dans ton code.
as const rend aussi le tableau readonly : impossible d'y faire .push() ou de réassigner un élément après coup. C'est voulu — mais surprend parfois au premier abord.
3. Les template literal types
TypeScript permet de construire des types à partir de la syntaxe des template strings JavaScript. Utile pour typer des conventions de nommage, des routes, ou des classes CSS.
type Direction = "top" | "right" | "bottom" | "left";
type Spacing = "sm" | "md" | "lg";
type MarginClass = `margin-${Direction}-${Spacing}`;
// "margin-top-sm" | "margin-top-md" | "margin-top-lg"
// | "margin-right-sm" | ... (12 combinaisons générées automatiquement)
Exemple concret pour typer des routes internes, comme celles de ton navLinks :
type Slug = "keller" | "n8n" | "cabinet-osteopathie" | "zelda";
type ProjectRoute = `/projets/${Slug}`;
function goToProject(route: ProjectRoute) {
// route est forcément une URL de projet valide, vérifiée à la compilation
}
goToProject("/projets/keller"); // ✅ valide
goToProject("/projets/inexistant"); // ❌ erreur de compilation
4. Vérification exhaustive avec never
Quand tu gères une union discriminée (un type avec plusieurs variantes identifiées par un champ commun), il est facile d'oublier un cas dans un switch. L'astuce never transforme cet oubli en erreur de compilation plutôt qu'en bug silencieux à l'exécution.
type Experience =
| { type: "work"; company: string }
| { type: "formation"; company: string };
function describe(exp: Experience) {
switch (exp.type) {
case "work":
return `Poste chez ${exp.company}`;
case "formation":
return `Formation chez ${exp.company}`;
default:
// Si tous les cas sont couverts, exp est ici de type "never"
// Si on ajoute une 3e variante au type Experience sans la gérer,
// cette ligne devient une ERREUR DE COMPILATION
const _exhaustiveCheck: never = exp;
return _exhaustiveCheck;
}
}
Cette technique est précieuse dès que tu ajoutes un nouveau type d'expérience (comme "formation" vs "work" dans ton experiences) : le compilateur te signale immédiatement partout où ce nouveau cas n'est pas encore géré, au lieu de le découvrir en production.
5. keyof typeof pour typer un objet
Pour typer les clés d'un objet déjà existant sans dupliquer sa définition, la combinaison keyof typeof fait le travail en une ligne — pratique pour remplacer un enum par un objet simple (plus flexible, plus léger à l'usage).
const icons = {
react: ReactIcon,
nextjs: NextIcon,
figma: FigmaIcon,
typescript: TypeScriptIcon,
} as const;
type IconName = keyof typeof icons;
// "react" | "nextjs" | "figma" | "typescript"
// généré automatiquement depuis les clés de l'objet icons
function getIcon(name: IconName) {
return icons[name]; // TypeScript sait que name est forcément une clé valide
}
getIcon("react"); // ✅ valide
getIcon("vue"); // ❌ erreur, "vue" n'existe pas dans icons
Pourquoi c'est préférable à un enum : si tu ajoutes une icône dans l'objet icons, IconName se met à jour automatiquement — une seule source de vérité, pas de risque de désynchronisation entre l'objet et le type.
En résumé
| Astuce | À utiliser quand |
|---|---|
satisfies |
Tu veux vérifier un type sans perdre la précision des valeurs littérales |
as const |
Tu veux figer un tableau/objet et en extraire une union de types |
| Template literal types | Tu veux typer des chaînes suivant un pattern (routes, classes CSS, clés) |
never exhaustif |
Tu veux que le compilateur détecte les cas manquants dans un switch |
keyof typeof |
Tu veux typer les clés d'un objet existant sans dupliquer la liste |
Ces cinq astuces partagent un point commun : elles déplacent des vérifications qui se feraient normalement à l'exécution (ou pas du tout) vers la compilation. Le résultat concret sur un projet comme ton portfolio ou e-magine-academy : moins de fautes de frappe silencieuses dans les slug, moins d'oublis lors de l'ajout d'un nouveau type de contenu, et une autocomplétion VSCode nettement plus fiable.
