TypeScript: Interfaces vs types

715

Quelle est la différence entre ces déclarations (interface vs type)?

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};
wonea
la source
4
Trouvé cet article expliquant les différences - medium.com/@martin_hotell/…
Sandeep GB
1
Différence de
Michael Freidgeim

Réponses:

574

Selon la spécification du langage TypeScript :

Contrairement à une déclaration d'interface, qui introduit toujours un type d'objet nommé, une déclaration d'alias de type peut introduire un nom pour tout type de type, y compris les types primitifs, d'union et d'intersection.

La spécification poursuit en mentionnant:

Les types d'interface présentent de nombreuses similitudes avec les alias de type pour les littéraux de type objet, mais comme les types d'interface offrent plus de fonctionnalités, ils sont généralement préférés aux types d'alias. Par exemple, le type d'interface

interface Point {
    x: number;
    y: number;
}

pourrait être écrit comme l'alias de type

type Point = {
    x: number;
    y: number;
};

Cependant, cela signifie que les capacités suivantes sont perdues:

  • Une interface peut être nommée dans une clause extend ou implements, mais un alias de type pour un littéral de type objet ne peut plus être vrai depuis TS 2.7.
  • Une interface peut avoir plusieurs déclarations fusionnées , mais pas un alias de type pour un littéral de type d'objet.
Bouleau binaire
la source
109
Que signifie «plusieurs déclarations fusionnées» dans la deuxième différence?
jrahhali
66
@jrahhali si vous définissez une interface deux fois, dactylographié les fusionne en une seule.
Andrey Fedorov
39
@jrahhali si vous définissez le type deux fois, la dactylographie vous donne une erreur
Andrey Fedorov
18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco
20
Je crois que le premier point extends or implementsn'est plus le cas. Le type peut être étendu et implémenté par a class. Voici un exemple typescriptlang.org/play/…
dark_ruby
779

Mise à jour 2019


Les réponses actuelles et la documentation officielle sont obsolètes. Et pour ceux qui découvrent TypeScript, la terminologie utilisée n'est pas claire sans exemples. Vous trouverez ci-dessous une liste des différences à jour.

1. Objets / fonctions

Les deux peuvent être utilisés pour décrire la forme d'un objet ou une signature de fonction. Mais la syntaxe diffère.

Interface

interface Point {
  x: number;
  y: number;
}

interface SetPoint {
  (x: number, y: number): void;
}

Alias ​​de type

type Point = {
  x: number;
  y: number;
};

type SetPoint = (x: number, y: number) => void;

2. Autres types

Contrairement à une interface, l'alias de type peut également être utilisé pour d'autres types tels que les primitives, les unions et les tuples.

// primitive
type Name = string;

// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };

// union
type PartialPoint = PartialPointX | PartialPointY;

// tuple
type Data = [number, string];

3. Étendre

Les deux peuvent être étendus, mais encore une fois, la syntaxe diffère. En outre, notez qu'une interface et un alias de type ne s'excluent pas mutuellement. Une interface peut étendre un alias de type et vice versa.

L'interface étend l'interface

interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }

L'alias de type étend l'alias de type

type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };

L'interface étend l'alias de type

type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }

L'alias de type étend l'interface

interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };

4. Instruments

Une classe peut implémenter une interface ou un alias de type, les deux de la même manière exacte. Notez cependant qu'une classe et une interface sont considérées comme des plans statiques. Par conséquent, ils ne peuvent pas implémenter / étendre un alias de type qui nomme un type d'union.

interface Point {
  x: number;
  y: number;
}

class SomePoint implements Point {
  x = 1;
  y = 2;
}

type Point2 = {
  x: number;
  y: number;
};

class SomePoint2 implements Point2 {
  x = 1;
  y = 2;
}

type PartialPoint = { x: number; } | { y: number; };

// FIXME: can not implement a union type
class SomePartialPoint implements PartialPoint {
  x = 1;
  y = 2;
}

5. Fusion de la déclaration

Contrairement à un alias de type, une interface peut être définie plusieurs fois et sera traitée comme une interface unique (les membres de toutes les déclarations étant fusionnés).

// These two declarations become:
// interface Point { x: number; y: number; }
interface Point { x: number; }
interface Point { y: number; }

const point: Point = { x: 1, y: 2 };
jabacchetta
la source
9
Si la documentation officielle est obsolète, où les informations que vous avez fournies peuvent-elles être confirmées?
iX3
60
Sur la base de ce post, il semble que la seule raison de choisir une interface plutôt qu'un alias de type soit si vous souhaitez utiliser la fonctionnalité de fusion de déclaration (point 5) des interfaces. Au-delà de cela, ils sont équivalents (et je dirais que les alias de type offrent une syntaxe plus concise).
maxedison le
17
J'utilise toujours des interfaces pour le type d'objet littéral, sinon l'utilisation de types a plus de sens, je pense également que la fusion de déclarations ne devrait pas être utilisée de toute façon, en fait, je ne m'attendrai jamais à ce qu'une interface soit déclarée dans un autre fichier du projet avec certains propriétés supplémentaires, la vérification de type est effectuée à l'origine pour vous faciliter la vie et ne pas la rendre plus difficile avec ces interfaces de type ninja: D
Ahmed Kamal
8
Donc, fondamentalement, c'est un choix «presque personnel» pour ce que nous nous sentons vraiment à l'aise d'utiliser? En dehors d'une raison, vous pouvez simplement utiliser typeou interface? Je ne sais toujours pas quand je devrais utiliser l'un ou l'autre.
Joseph Briggs
7
Quelqu'un pourrait-il expliquer pourquoi vous souhaitez fusionner l'interface? Cela me semble potentiellement déroutant. Pourquoi voudriez-vous étaler la définition de votre interface sur différents blocs?
Vanquish46
95

Depuis TypeScript 3.2 (novembre 2018), ce qui suit est vrai:

entrez la description de l'image ici

Karol Majewski
la source
9
Pourriez-vous s'il vous plaît fournir plus d'informations sur la façon dont le tableau / l'image que vous avez fourni a été généré? par exemple le code source ou des liens vers la documentation
iX3
23
oui, je voulais dire la source du contenu, pas sa présentation.
iX3
3
Je ne crois pas qu'une classe puisse étendre un type ou une interface, et je ne vois pas vraiment pourquoi vous voudriez ??
Dan King
7
Évitez de publier des images de texte, mais incluez plutôt le texte réel directement dans votre message. Les images de texte ne sont pas facilement analysables ou consultables et ne sont pas accessibles aux utilisateurs malvoyants.
Andrew Marshall
2
Ce tableau n'a aucune source pour prendre en charge son contenu et je ne m'y fierais pas. Par exemple, vous pouvez définir des types récursifs à l'aide typede certaines limitations (et à partir de TypeScript 3.7, ces limitations ont également disparu). Les interfaces peuvent étendre les types. Les classes peuvent implémenter des types. De plus, la présentation des données sous forme de capture d'écran d'un tableau les rend complètement inaccessibles aux personnes malvoyantes.
Michał Miszczyszyn
5

Exemples avec types:

// crée une arborescence pour un objet. Vous ne pouvez pas faire la même chose avec l'interface en raison du manque d'intersection (&)

type Tree<T> = T & { parent: Tree<T> };

// tapez pour restreindre une variable pour n'affecter que quelques valeurs. Les interfaces n'ont pas d'union (|)

type Choise = "A" | "B" | "C";

// grâce aux types, vous pouvez déclarer un type NonNullable grâce à un mécanisme conditionnel.

type NonNullable<T> = T extends null | undefined ? never : T;

Exemples avec interface:

// vous pouvez utiliser l'interface pour la POO et utiliser des 'implements' pour définir le squelette objet / classe

interface IUser {
    user: string;
    password: string;
    login: (user: string, password: string) => boolean;
}

class User implements IUser {
    user = "user1"
    password = "password1"

    login(user: string, password: string) {
        return (user == user && password == password)
    }
}

// vous pouvez étendre les interfaces avec d'autres interfaces

    interface IMyObject {
        label: string,
    }

    interface IMyObjectWithSize extends IMyObject{
        size?: number
    }
Przemek Struciński
la source
-2

la documentation a expliqué

  • Une différence est que les interfaces créent un nouveau nom qui est utilisé partout. Les alias de type ne créent pas de nouveau nom - par exemple, les messages d'erreur n'utilisent pas le nom d'alias. Dans les anciennes versions de TypeScript, les alias de type ne pouvaient pas être étendus ou implémentés à partir (ni étendre / implémenter d'autres types). Depuis la version 2.7, les alias de type peuvent être étendus en créant un nouveau type d'intersection
  • D'un autre côté, si vous ne pouvez pas exprimer une forme avec une interface et que vous devez utiliser un type union ou tuple, les alias de type sont généralement la solution.

Interfaces et alias de type

Liu Lei
la source