BaliseTonSite

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-line

9.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 TS

9.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 Theme

9.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

Verifie tes acquis

3 questions pour valider ce chapitre

1. Pourquoi eviter le type any autant que possible ?

Valide et sauvegarde ce chapitre

Ne perds pas le fil de ton apprentissage. Chaque QCM terminé sauvegarde ton score. Crée ton profil gratuitement pour débloquer toutes les évaluations du site et retrouver tes résultats plus tard.

Commencer l'aventure
Déjà membre ?Connecte-toi