> type ou interface en TypeScript ? Différences réelles (extension, fusion de déclaration, unions, primitifs), quand utiliser l'un ou l'autre, et recommandations concrètes avec exemples.

*Source : https://coder-studio.com/tutoriels/type-vs-interface-typescript/*

---

[// TypeScript](https://coder-studio.com/tutoriels/)

# type vs interface en TypeScript : quelle différence ?

Par **Kévin Papot** · publié le 6 mars 2026

C’est l’une des questions récurrentes quand on apprend TypeScript : faut-il déclarer ses structures avec `type` ou avec `interface` ? Les deux permettent de décrire la forme d’un objet, et dans la majorité des cas, ils sont interchangeables. Mais il existe des différences réelles qui, selon le contexte, penchent en faveur de l’un ou de l’autre. Ce guide fait le tri, sans dogmatisme.

## Le point de départ : deux façons de décrire un objet

Pour typer un objet, `type` et `interface` produisent un résultat quasi identique.

```
interface UtilisateurI {
  id: number;
  nom: string;
  actif?: boolean;
}

type UtilisateurT = {
  id: number;
  nom: string;
  actif?: boolean;
};
```

Les deux déclarations sont utilisables exactement de la même manière, et TypeScript signalera les mêmes erreurs si vous oubliez une propriété ou vous trompez de type. Si vous découvrez le typage statique, notre [guide TypeScript](https://coder-studio.com/tutoriels/typescript-guide/) explique d’abord comment poser ces bases.

La question n’est donc pas « lequel fonctionne », mais « lequel est le plus adapté selon ce que vous voulez faire ». Voyons les vraies divergences.

## Différence 1 : `type` gère les unions et les primitifs

C’est la distinction la plus importante. Un `type` peut représenter **bien plus qu’un objet** : une union, un type primitif renommé, un tuple, une valeur littérale. Une `interface`, elle, décrit toujours une forme d’objet (ou de fonction/classe).

```
// Ces déclarations sont IMPOSSIBLES avec interface
type Statut = "brouillon" | "publie" | "archive"; // union de littéraux
type Id = string | number;                        // union de primitifs
type Coordonnees = [number, number];              // tuple
type Nom = string;                                // alias d'un primitif

// interface ne peut pas faire ceci
// interface Statut = "brouillon" | "publie";  ❌ syntaxe invalide
```

Dès que vous avez besoin d’une **union**, d’un **tuple** ou d’un **alias de primitif**, `type` est la seule option. C’est de loin le cas d’usage qui tranche le plus souvent la décision.

## Différence 2 : la fusion de déclaration (declaration merging)

Une `interface` possède une capacité que `type` n’a pas : si vous la déclarez **deux fois avec le même nom**, TypeScript **fusionne** les deux définitions. C’est ce qu’on appelle la fusion de déclaration.

```
interface Fenetre {
  titre: string;
}

interface Fenetre {
  largeur: number;
}

// Les deux déclarations fusionnent automatiquement
const f: Fenetre = { titre: "Accueil", largeur: 1024 }; // ✅
```

Avec `type`, redéclarer le même nom provoque une erreur :

```
type Fenetre = { titre: string };
type Fenetre = { largeur: number }; // ❌ Erreur : identifiant dupliqué
```

Cette fusion peut sembler anecdotique, mais elle est **essentielle** pour étendre des types tiers ou globaux : ajouter une propriété à `Window`, enrichir les types d’une bibliothèque via un fichier de déclaration, etc. C’est la raison historique pour laquelle beaucoup de bibliothèques exposent leurs contrats sous forme d’`interface`.

## Différence 3 : l’extension

Les deux permettent de composer, mais avec une syntaxe différente. `interface` utilise `extends`, tandis que `type` utilise l’intersection `&`.

```
// Avec interface
interface Animal {
  nom: string;
}
interface Chien extends Animal {
  race: string;
}

// Avec type
type AnimalT = {
  nom: string;
};
type ChienT = AnimalT & {
  race: string;
};
```

Le résultat est équivalent. Une `interface` peut même étendre un `type` (et inversement, un `type` peut composer une `interface`), donc les deux mondes cohabitent sans friction.

```
type Base = { id: number };
interface Enrichi extends Base { // interface peut étendre un type objet
  nom: string;
}
```

Une nuance de performance existe : `extends` sur des interfaces produit un « cache » que TypeScript exploite, ce qui peut rendre la vérification plus rapide sur de très grandes hiérarchies de types que les intersections `&` répétées. En pratique, cela ne se ressent que sur des bases de code massives.

## Différence 4 : les types calculés

`type` va plus loin dès qu’il s’agit de **transformer** un type existant. Types mappés, types conditionnels, opérateurs sur les clés : tout cela relève du territoire de `type`.

```
interface Utilisateur {
  id: number;
  nom: string;
  email: string;
}

// Type mappé : rendre tout optionnel (impossible avec interface)
type UtilisateurPartiel = {
  [K in keyof Utilisateur]?: Utilisateur[K];
};

// Type conditionnel
type NonNul<T> = T extends null | undefined ? never : T;
```

Ces constructions n’ont pas d’équivalent en `interface`. Toute la « programmation au niveau des types » repose donc sur `type`.

## Tableau récapitulatif

Capacité

`interface`

`type`

Décrire un objet

✅

✅

Unions (`A | B`)

❌

✅

Tuples, primitifs, littéraux

❌

✅

Fusion de déclaration

✅

❌

Extension

`extends`

`&`

Types mappés / conditionnels

❌

✅

Étendre un type tiers global

✅ (idéal)

limité

## Quand utiliser l’un ou l’autre

Plutôt que de trancher dogmatiquement, voici une règle pragmatique adoptée par une grande partie de l’écosystème.

**Utilisez `interface` par défaut pour les objets et les contrats publics.** Notamment les props de composants, les formes de données d’API, les contrats d’une bibliothèque. Vous bénéficiez de messages d’erreur souvent plus lisibles, de la fusion de déclaration si un tiers doit étendre votre type, et d’une intention claire (« ceci est une structure »).

```
// Contrat clair d'un composant : interface
interface ButtonProps {
  label: string;
  onClick: () => void;
  variante?: "primaire" | "secondaire";
}
```

**Utilisez `type` dès que vous sortez du simple objet.** Union, tuple, alias de primitif, type calculé, ou combinaison de plusieurs types.

```
// Union et transformation : type
type Theme = "clair" | "sombre" | "auto";
type Resultat<T> = { ok: true; valeur: T } | { ok: false; erreur: string };
```

## L’essentiel

Dans 80 % des cas, `type` et `interface` sont interchangeables et le choix relève surtout de la convention d’équipe. Les critères qui tranchent réellement :

-   Besoin d’une **union, d’un tuple ou d’un primitif** ? → `type`, obligatoire.
-   Besoin de **fusion de déclaration** ou d’étendre un type global ? → `interface`.
-   Besoin de **types calculés** (mappés, conditionnels) ? → `type`.
-   Simple objet ou props de composant ? → `interface` par convention, mais `type` fonctionne aussi.

Le plus important n’est pas de choisir « le bon », mais de rester **cohérent** dans un même projet. Fixez une règle d’équipe et tenez-vous-y : c’est ce qui rend le code lisible sur la durée.

## À lire ensuite

-   [Les generics en TypeScript : le guide](https://coder-studio.com/tutoriels/generics-typescript/)
-   [TypeScript : pourquoi et comment l’adopter](https://coder-studio.com/tutoriels/typescript-guide/)
-   [React : le guide pour bien débuter](https://coder-studio.com/tutoriels/react-guide-debutant/)
