TypeScript enrichit JavaScript d’un système de typage statique qui renfroce la fiabilité et la maintenabilité du code. Parmi ses fonctionnalités essentielles, les interfaces et les type aliases (ou types) sont deux outils centraux pour définir la forme des données. Bien qu’ils soient souvent interchangeables, leurs capacités diffèrent. Maîtriser leurs spécificités permet de choisir l’outil le plus adopté à chaque situation.
Les interfaces
Les interfaces, introduites dès les premières versions de TypeScript, s’inscrivent dans la logique de la programmation orientée objet. Elles permettent de décrire la structure d’un objet et peuvent être étendues ou implémentées.
Exemple de base
interface Produit {
nom: string;
prix: number;
}
Héritage entre interfaces
Un des atouts majeurs des interfaces est la possibilité d’en étendre d’autres, facilitant la construction de types plus spécifiques.
interface Personne {
prenom: string;
}
interface Employe extends Personne {
poste: string;
}
const employe: Employe = { prenom: 'Sophie', poste: 'Développeuse' };
Utilisation avec les classes
Une interface peut définir un contrat que les classes doivent respecter via le mot-clé implements.
interface Affichable {
afficher: () => void;
}
class Facture implements Affichable {
afficher() {
console.log('Facture émise.');
}
}
Fusion de déclarations
Les interfaces supportent la fusion : si plusieurs interfaces portent le même nom dans le même scope, elles sont automatiquement combinées. Cette fonctionnalité peut être pratique, mais il faut l’utiliser avec prudence.
interface Utilisateur {
email: string;
}
interface Utilisateur {
actif: boolean;
}
const u: Utilisateur = { email: 'a@b.com', actif: true };
Les types (type aliases)
Les types, plus flexibles, permetent de définir des unions, des intersections ou des alias pour des types primitifs.
Union de types
Les types peuvent exprimer qu’une valeur peut avoir plusieurs formes, ce que les interfaces ne peuvent pas faire directement.
type Id = string | number;
type Statut = 'actif' | 'inactif';
Impossibilité de fusion
Contrairement aux interfaces, un nom de type ne peut pas être redéclaré.
type Cible = {
id: number;
};
// Erreur : Identificateur en conflit
type Cible = {
nom: string;
};
Combinaisons et transformations
Les types s’avèrent puissants pour créer de nouveaux types à partir d’existants, notamment avec les utilitaires intégrés.
type Adherent = {
nom: string;
age: number;
email: string;
};
type AdherentPartiel = Partial<Adherent>;
const partiel: AdherentPartiel = { nom: 'Marc' };
type SeulementNom = Pick<Adherent, 'nom'>;
const nomSeul: SeulementNom = { nom: 'Marc' };
type AdherentOuAdmin = Adherent | { admin: boolean };
Quand utiliser quoi ?
- Interface : pour décrire la forme d’objets ou de classes lorsque l’héritage est nécessaire, ou quand on souhaite une fusion de déclarations.
- Type : pour les unions, les intersections, les alias de types primitifs, les tuples, ou toute combinaison complexe qui ne correspond pas à un objet simple.
En choisissant l’outil adapté, vous rendez votre code plus lisible et plus facile à faire évoluer. La typage statique de TypeScript gagne en expressivité quand on sait tirer parti de ces deux mécanismes.