BaliseTonSite

Types Avancés

Le niveau supérieur - unions discriminées, types mappés et conditionnels.

7.1Unions et types littéraux

TypeScripttypescript
// Union : un type OU un autre
type StringOuNumber = string | number
let id: StringOuNumber = "abc-123"
id = 42  // ✅ Aussi valide

// Types littéraux : des valeurs EXACTES comme types
type Direction = "haut" | "bas" | "gauche" | "droite"
let mouvement: Direction = "haut"
// mouvement = "diagonal"    // ❌ Pas dans l'union

// Littéraux numériques
type DeFace = 1 | 2 | 3 | 4 | 5 | 6
let lancer: DeFace = 4
// lancer = 7                // ❌

// Préféré aux enums pour la légèreté
type Theme = "light" | "dark" | "system"
type Taille = "sm" | "md" | "lg" | "xl"
type HttpMethode = "GET" | "POST" | "PUT" | "DELETE"

7.2Narrowing (rétrécissement de type)

Quand tu as un type union, TypeScript te demande de vérifier le type avant de l'utiliser :

TypeScripttypescript
function traiter(valeur: string | number) {
  // typeof guard
  if (typeof valeur === "string") {
    // Ici, TypeScript sait que valeur est string
    return valeur.toUpperCase()
  }
  // Ici, c'est forcément number
  return valeur.toFixed(2)
}

// instanceof guard (pour les classes)
function formater(date: Date | string): string {
  if (date instanceof Date) {
    return date.toLocaleDateString("fr-FR")
  }
  return date  // C'est un string
}

// "in" guard (pour les objets)
interface Chat { miauler(): void }
interface Chien { aboyer(): void }

function faireDuBruit(animal: Chat | Chien) {
  if ("miauler" in animal) {
    animal.miauler()     // TypeScript sait que c'est un Chat
  } else {
    animal.aboyer()      // TypeScript sait que c'est un Chien
  }
}

7.3Unions discriminées (Discriminated Unions)

Le pattern le plus puissant pour gérer des variants. Chaque type a une propriété commune qui sert de "badge d'identification" :

TypeScripttypescript
// Chaque variante a un "type" discriminant
interface ChargementEnCours {
  statut: "chargement"
}

interface ChargementReussi<T> {
  statut: "succes"
  donnees: T
}

interface ChargementEchoue {
  statut: "erreur"
  message: string
}

type ChargementState<T> =
  | ChargementEnCours
  | ChargementReussi<T>
  | ChargementEchoue

// TypeScript rétrécit le type grâce au discriminant
function afficher(state: ChargementState<string[]>) {
  switch (state.statut) {
    case "chargement":
      return "Chargement..."

    case "succes":
      // TS sait que state.donnees existe ici
      return state.donnees.join(", ")

    case "erreur":
      // TS sait que state.message existe ici
      return `Erreur : ${state.message}`
  }
}

7.4Type Guards personnalisés

TypeScripttypescript
// Créer son propre garde de type
interface Poisson { nager(): void }
interface Oiseau { voler(): void }

// Le retour "animal is Poisson" est un type predicate
function estPoisson(animal: Poisson | Oiseau): animal is Poisson {
  return (animal as Poisson).nager !== undefined
}

function deplacer(animal: Poisson | Oiseau) {
  if (estPoisson(animal)) {
    animal.nager()    // ✅ TypeScript sait que c'est un Poisson
  } else {
    animal.voler()    // ✅ TypeScript sait que c'est un Oiseau
  }
}

// Garde utile au quotidien
function estDefini<T>(valeur: T | null | undefined): valeur is T {
  return valeur !== null && valeur !== undefined
}

const valeurs = [1, null, 3, undefined, 5]
const definies = valeurs.filter(estDefini)  // type: number[]

7.5Types mappés

Transforme un type existant en un autre, propriété par propriété :

TypeScripttypescript
// Rendre toutes les propriétés optionnelles (comme Partial)
type MonPartial<T> = {
  [K in keyof T]?: T[K]
}

// Rendre toutes les propriétés readonly
type MonReadonly<T> = {
  readonly [K in keyof T]: T[K]
}

// Rendre toutes les propriétés nullable
type Nullable<T> = {
  [K in keyof T]: T[K] | null
}

interface Formulaire {
  nom: string
  email: string
  age: number
}

type FormulaireNullable = Nullable<Formulaire>
// { nom: string | null; email: string | null; age: number | null }

// Mapper les clés vers un nouveau type
type Drapeaux<T> = {
  [K in keyof T]: boolean
}

type FormulaireValide = Drapeaux<Formulaire>
// { nom: boolean; email: boolean; age: boolean }

7.6Types conditionnels

TypeScripttypescript
// Syntaxe : T extends U ? X : Y
type EstString<T> = T extends string ? "oui" : "non"

type Test1 = EstString<string>    // "oui"
type Test2 = EstString<number>    // "non"

// Extraire le type des éléments d'un tableau
type ElementDe<T> = T extends (infer E)[] ? E : never

type A = ElementDe<string[]>     // string
type B = ElementDe<number[]>     // number
type C = ElementDe<boolean>      // never (pas un tableau)

// Exclure des types d'une union
type SansNull<T> = T extends null | undefined ? never : T

type Propre = SansNull<string | number | null | undefined>
// string | number

// C'est exactement ce que fait NonNullable<T> !
type Aussi = NonNullable<string | number | null>  // string | number

7.7Template Literal Types

TypeScripttypescript
// Types basés sur des chaînes de caractères
type Couleur = "rouge" | "bleu" | "vert"
type Taille = "petit" | "moyen" | "grand"

// Combinaison automatique !
type ClasseCSS = `${Taille}-${Couleur}`
// "petit-rouge" | "petit-bleu" | "petit-vert"
// | "moyen-rouge" | "moyen-bleu" | "moyen-vert"
// | "grand-rouge" | "grand-bleu" | "grand-vert"

// Exemple concret : événements
type Evenement = "click" | "scroll" | "keypress"
type HandlerName = `on${Capitalize<Evenement>}`
// "onClick" | "onScroll" | "onKeypress"

// Manipulation de chaînes au niveau des types
type Majuscule = Uppercase<"hello">      // "HELLO"
type Minuscule = Lowercase<"HELLO">      // "hello"
type Capitalise = Capitalize<"hello">    // "Hello"
type Decapitalise = Uncapitalize<"Hello">  // "hello"

Verifie tes acquis

3 questions pour valider ce chapitre

1. Qu'est-ce que le "narrowing" en TypeScript ?

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