Quelle est la différence entre ces instructions (interface vs type)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
Selon le 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 primitive, union, et types d'intersection.
La spécification continue à mentionner:
Les types d'interface présentent de nombreuses similitudes avec les alias de type des littéraux de type d'objet, mais étant donné que les types d'interface offrent davantage de fonctionnalités, ils sont généralement préférés aux alias de type. 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 extended ou implements, mais un alias de type pour un objet littéral ne peut pasCe n'est plus vrai depuis TS 2.7.- Une interface peut avoir plusieurs déclarations fusionnées , mais un alias de type pour un objet de type littéral ne le peut pas.
Les réponses actuelles et le 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 les plus récentes.
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;
}
Tapez un alias
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void;
Contrairement à une interface, le type alias 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];
Les deux peuvent être étendus, mais là encore, la syntaxe est différente. En outre, notez qu'une interface et un alias de type ne sont pas mutuellement exclusifs. Une interface peut étendre un alias de type, et inversement.
Interface étend l'interface
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
Le type alias étend le type alias
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
L'interface étend le type alias
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
Le type alias étend l'interface
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
Une classe peut implémenter une interface ou un alias de type, les deux de la même manière. 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;
}
Contrairement à un alias de type, une interface peut être définie plusieurs fois et sera traitée comme une interface unique (avec les membres de toutes les déclarations en cours de fusion).
// 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 };
https://www.typescriptlang.org/docs/handbook/advanced-types.html
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.
// crée une arborescence pour un objet. Vous ne pouvez pas faire la même chose avec l'interface à cause du manque d'intersection (&)
type Tree<T> = T & { parent: Tree<T> };
// tapez pour restreindre une variable à 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 le type NonNullable grâce à un mécanisme conditionnel.
type NonNullable<T> = T extends null | undefined ? never : T;
// vous pouvez utiliser l'interface pour OOP et utiliser 'implements' pour définir le squelette d'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 des interfaces avec d'autres interfaces
interface IMyObject {
label: string,
}
interface IMyObjectWithSize extends IMyObject{
size?: number
}
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 versions antérieures de TypeScript, les alias de type ne pouvaient pas être étendus ni implémentés (ils ne pouvaient pas non plus étendre/implémenter d'autres types). A partir de la version 2.7, les alias de types peuvent être étendus en créant un nouveau type d'intersection
- D'autre part, si vous ne pouvez pas exprimer une forme avec une interface et que vous devez utiliser un type d'union ou de tuple, les alias de type sont généralement la solution.