Leçon 2 / 8
Leçon 02 · TypeScript

Types de base

Les types primitifs

TypeScript hérite des types primitifs de JavaScript, mais te demande d'être explicite sur ce que chaque variable peut contenir. Voici les six types primitifs fondamentaux :

  • string — du texte
  • number — un nombre (entier ou décimal)
  • boolean — vrai ou faux
  • null — absence de valeur, intentionnelle
  • undefined — valeur non assignée
  • symbol — identifiant unique (usage avancé)

En TypeScript, tu annoies le type après le nom de la variable avec : type :

TypeScript
let prenom: string = "Alice";
let age: number = 28;
let estActif: boolean = true;
let valeur: null = null;
let inconnu: undefined = undefined;

// TypeScript peut inférer le type automatiquement
let ville = "Paris";  // TypeScript sait que c'est un string
ville = 42;          // ❌ Erreur : Type 'number' is not assignable to type 'string'

Cette dernière ligne est la force de TypeScript : une fois qu'une variable a un type, tu ne peux plus lui assigner un autre type. Le compilateur t'avertit avant même l'exécution.

Tableaux et tuples

Tableaux — string[] et Array<number>

Pour typer un tableau, tu as deux syntaxes équivalentes :

TypeScript
// Syntaxe 1 : type + []
const prenoms: string[] = ["Alice", "Bob", "Clara"];
const scores: number[] = [10, 42, 99];

// Syntaxe 2 : Array générique (identique)
const ids: Array<number> = [1, 2, 3];

// TypeScript empêche le mélange de types
prenoms.push("David");  // ✅ OK
prenoms.push(42);       // ❌ Erreur : Argument of type 'number' is not assignable

Tuples — longueur et types fixes

Un tuple est un tableau avec un nombre fixe d'éléments, chacun avec un type précis. Utile quand l'ordre a un sens métier.

TypeScript
// Tuple : [string, number]
// Premier élément : string, deuxième : number
let utilisateur: [string, number] = ["Alice", 28];

console.log(utilisateur[0]);  // "Alice"
console.log(utilisateur[1]);  // 28

// Erreur si on inverse les types
let erreur: [string, number] = [28, "Alice"];  // ❌ Type 'number' is not assignable to type 'string'

Enum — valeurs nommées

Un enum permet de définir un ensemble de valeurs nommées. Au lieu d'utiliser des chaînes magiques ou des nombres bruts, tu donnes des noms explicites à tes états.

Enum numérique (par défaut)

TypeScript
enum Direction {
  Haut,    // 0
  Bas,     // 1
  Gauche,  // 2
  Droite   // 3
}

let mouvement: Direction = Direction.Haut;
console.log(mouvement);  // 0

// On peut aussi partir d'une valeur personnalisée
enum Priorite {
  Basse = 1,
  Moyenne = 5,
  Haute = 10
}

Enum string — plus lisible

Les enums string sont préférables dans la plupart des projets car ils produisent des valeurs lisibles en débogage.

TypeScript
enum Statut {
  EnAttente = "EN_ATTENTE",
  Actif     = "ACTIF",
  Inactif   = "INACTIF"
}

let etatCompte: Statut = Statut.EnAttente;
console.log(etatCompte);  // "EN_ATTENTE" — bien plus lisible qu'un 0 !

any et unknown — une différence cruciale

Le type any — la porte de sortie

Le type any désactive complètement la vérification de type pour une variable. Elle peut recevoir n'importe quoi, et tu peux en faire n'importe quoi — TypeScript abandonne toute surveillance.

TypeScript
let nimportequoi: any;
nimportequoi = "texte";
nimportequoi = 42;
nimportequoi = true;
nimportequoi.methodeInexistante();  // TypeScript ne dit rien — mais plantera à l'exécution !
⚠️

Évite any autant que possible. C'est l'équivalent de retirer ta ceinture de sécurité. Tu perds tous les bénéfices de TypeScript : pas d'autocomplétion, pas de vérification d'erreurs, risque de bugs à l'exécution. Si tu utilises beaucoup de any, tu n'utilises plus vraiment TypeScript.

Le type unknown — la version sûre

unknown est le pendant sûr de any. Tu peux y stocker n'importe quoi, mais TypeScript t'oblige à vérifier le type avant d'utiliser la valeur.

TypeScript
function traiterDonnee(valeur: unknown): string {
  // ❌ Impossible sans vérification
  // return valeur.toUpperCase(); // Erreur : Object is of type 'unknown'

  // ✅ On vérifie d'abord le type
  if (typeof valeur === "string") {
    return valeur.toUpperCase();  // OK, TypeScript sait que c'est un string ici
  }
  return "Valeur inconnue";
}

Règle : si tu dois accepter une valeur de type indéterminé (réponse d'API, donnée utilisateur), préfère unknown à any. Cela te force à valider les données avant usage, ce qui évite les erreurs à l'exécution.

never et void

void — fonctions sans valeur de retour

Une fonction qui ne retourne rien a le type de retour void. C'est le cas classique d'une fonction qui affiche quelque chose ou modifie un état sans renvoyer de valeur.

TypeScript
function afficherMessage(message: string): void {
  console.log(message);
  // Pas de return — la fonction ne renvoie rien
}

never — fonctions qui ne retournent jamais

never est plus radical : c'est le type d'une fonction qui ne se termine jamais normalement — soit elle lance une exception, soit elle tourne en boucle infinie. Utile pour les fonctions d'erreur fatale.

TypeScript
// Lance toujours une exception → ne retourne jamais
function erreurFatale(message: string): never {
  throw new Error(message);
}

// Boucle infinie → ne retourne jamais
function boucleInfinie(): never {
  while (true) {
    // traitement...
  }
}

À retenir : void = la fonction se termine mais sans valeur utile. never = la fonction ne se termine pas normalement.

Union types — plusieurs types possibles

Un union type permet à une variable d'accepter plusieurs types différents, séparés par le symbole |.

TypeScript
// Cette variable peut être un string OU un number
let identifiant: string | number;
identifiant = "abc-123";  // ✅ OK
identifiant = 42;        // ✅ OK
identifiant = true;      // ❌ Erreur : boolean n'est pas dans l'union

Type narrowing avec typeof

Quand une variable peut avoir plusieurs types, TypeScript exige que tu précises le type avant d'utiliser des méthodes spécifiques. C'est le type narrowing.

TypeScript
function formaterIdentifiant(id: string | number): string {
  if (typeof id === "string") {
    // Ici, TypeScript sait que id est un string
    return id.toUpperCase();
  }
  // Ici, TypeScript sait que id est forcément un number
  return id.toString().padStart(6, "0");
}

console.log(formaterIdentifiant("abc"));   // "ABC"
console.log(formaterIdentifiant(42));    // "000042"

Type aliases — nommer ses types

Le mot-clé type permet de créer un alias pour un type existant ou complexe. Pratique pour ne pas répéter un union type partout dans le code.

TypeScript
// Créer un alias pour un type composé
type UserId = string | number;
type Coordonnees = [number, number];  // tuple latitude, longitude
type Callback = (erreur: string | null) => void;

// Utilisation : plus lisible qu'un union type répété
function trouverUtilisateur(id: UserId): void {
  console.log("Recherche ID :", id);
}

const position: Coordonnees = [48.8566, 2.3522];  // Paris

Assertion de type

Parfois tu sais mieux que TypeScript quel est le type d'une valeur. Par exemple, après avoir vérifié une valeur provenant du DOM ou d'une API. L'assertion de type avec as te permet de dire à TypeScript : "Fais-moi confiance, je sais que c'est ce type."

TypeScript
// Récupérer un élément du DOM
const input = document.getElementById("monInput") as HTMLInputElement;
// Sans "as" : TypeScript voit HTMLElement | null, pas d'accès à .value
// Avec "as" : on peut accéder à .value directement
console.log(input.value);

// Double assertion — quand le type source est trop éloigné
// D'abord vers unknown, puis vers le type cible
const valeurBrute: unknown = "Bonjour";
const longueur = (valeurBrute as unknown as string).length;
// À retenir
  • Les 6 types primitifs : string, number, boolean, null, undefined, symbol
  • Tableaux : string[] ou Array<string> — tuples : [string, number] pour des structures fixes
  • enum : valeurs nommées lisibles, préfère les enums string pour le débogage
  • any : désactive TypeScript — à éviter. unknown : valeur incertaine mais sûre, oblige à vérifier le type avant usage
  • void : fonction qui se termine sans valeur. never : fonction qui ne se termine pas (exception, boucle infinie)
  • Union types string | number + type narrowing avec typeof pour utiliser la bonne méthode
  • type aliases : nommer des types complexes pour les réutiliser
  • Assertion as Type : dire à TypeScript quel type tu attends — à utiliser avec parcimonie