Bonnes Pratiques
Les patterns des pros pour un code TypeScript exemplaire.
9.1Évite any comme la peste
TypeScripttypescript
// ❌ Le réflexe du débutant
function traiter(donnees: any): any {
return donnees.map((d: any) => d.valeur)
}
// ✅ Utilise unknown + type guard
function traiterSafe(donnees: unknown): string[] {
if (!Array.isArray(donnees)) {
throw new Error("Un tableau est attendu")
}
return donnees.map((d: { valeur: string }) => d.valeur)
}
// ✅ Utilise les génériques
function traiterGenerique<T extends { valeur: string }>(donnees: T[]): string[] {
return donnees.map(d => d.valeur)
}
// Les rares cas où any est acceptable :
// 1. Migration JS → TS progressive (temporaire)
// 2. Wrappers de bibliothèques très dynamiques
// 3. Toujours avec un // eslint-disable-next-line9.2Préfère les types stricts
TypeScripttypescript
// ❌ Trop vague
function envoyerEmail(options: object) { /* ... */ }
// ✅ Précis
interface EmailOptions {
destinataire: string
sujet: string
contenu: string
cc?: string[]
priorite?: "haute" | "normale" | "basse"
}
function envoyerEmail(options: EmailOptions) { /* ... */ }
// ❌ String trop large
function setTheme(theme: string) { /* ... */ }
// ✅ Union littérale
function setTheme(theme: "light" | "dark" | "system") { /* ... */ }
// ❌ Boolean trap
function creerBouton(texte: string, gros: boolean, rond: boolean) { /* ... */ }
creerBouton("OK", true, false) // Que veulent dire true et false ?
// ✅ Objet d'options
interface BoutonOptions {
texte: string
taille?: "sm" | "md" | "lg"
variante?: "rond" | "carre"
}
function creerBouton(options: BoutonOptions) { /* ... */ }
creerBouton({ texte: "OK", taille: "lg" }) // Clair !9.3Conventions de nommage
TypeScripttypescript
// ✅ Interfaces et types : PascalCase
interface UtilisateurProfil { /* ... */ }
type HttpMethode = "GET" | "POST"
// ✅ Variables et fonctions : camelCase
const nomUtilisateur = "Alice"
function calculerTTC(prix: number): number { /* ... */ }
// ✅ Constantes globales : SCREAMING_SNAKE_CASE
const API_BASE_URL = "https://api.example.com"
const MAX_TENTATIVES = 3
// ✅ Enums : PascalCase pour le nom, PascalCase pour les valeurs
enum Statut {
Actif = "ACTIF",
Inactif = "INACTIF"
}
// ✅ Génériques : lettre majuscule descriptive
function mapper<TInput, TOutput>(
items: TInput[],
transformer: (item: TInput) => TOutput
): TOutput[] {
return items.map(transformer)
}
// ❌ Ne préfixe PAS les interfaces avec "I"
// interface IUtilisateur { } // Style C#, pas idiomatique en TS9.4as const et satisfies
TypeScripttypescript
// as const - rend les valeurs immutables et littérales
const config = {
api: "https://api.example.com",
timeout: 5000,
retries: 3
} as const
// Type : { readonly api: "https://..."; readonly timeout: 5000; readonly retries: 3 }
const couleurs = ["rouge", "bleu", "vert"] as const
// Type : readonly ["rouge", "bleu", "vert"]
type Couleur = typeof couleurs[number] // "rouge" | "bleu" | "vert"
// satisfies - vérifie le type SANS le perdre
type Theme = {
primaire: string
secondaire: string
fond: string
}
const monTheme = {
primaire: "#2563eb",
secondaire: "#06b6d4",
fond: "#f8fafc"
} satisfies Theme
// monTheme garde ses types littéraux (#2563eb, etc.)
// mais TypeScript vérifie qu'il respecte Theme9.5Gestion d'erreurs typée
TypeScripttypescript
// Pattern Result - alternative aux exceptions
type Result<T, E = Error> =
| { success: true; data: T }
| { success: false; error: E }
function diviser(a: number, b: number): Result<number, string> {
if (b === 0) {
return { success: false, error: "Division par zéro" }
}
return { success: true, data: a / b }
}
const resultat = diviser(10, 3)
if (resultat.success) {
console.log(resultat.data) // TypeScript sait que data existe
} else {
console.error(resultat.error) // TypeScript sait que error existe
}
// Typer les erreurs des try/catch
try {
JSON.parse("invalid")
} catch (error) {
// error est "unknown" en TS 4.4+
if (error instanceof SyntaxError) {
console.error("JSON invalide:", error.message)
}
}9.6Migration JavaScript → TypeScript
1
Ajoute TypeScript au projet
npm install -D typescript @types/node + créer tsconfig.json avec allowJs: true.
2
Renomme les fichiers un par un
.js → .ts (ou .jsx → .tsx). Commence par les fichiers les plus simples.
3
Corrige les erreurs progressivement
Ajoute les types, remplace les any implicites. Utilise // @ts-expect-error temporairement si besoin.
4
Active strict progressivement
Commence sans strict, puis active les options une par une : strictNullChecks, noImplicitAny...
JSONjson
// tsconfig.json pour une migration douce
{
"compilerOptions": {
"allowJs": true, // Accepte les .js
"checkJs": false, // Ne vérifie pas les .js
"strict": false, // Activer progressivement
"noImplicitAny": false, // Activer en dernier
"target": "ES2022",
"module": "ESNext"
},
"include": ["src/**/*"]
}9.7Checklist du bon projet TypeScript
strict: true activé
Zéro any (ou justifié)
Types explicites pour les API publiques
Utility Types au lieu de duplication
Unions discriminées pour les variants
import type pour les types-only imports
Path aliases configurés (@/)
ESLint + @typescript-eslint
Fichiers .d.ts pour les libs JS sans types