TypeScript: interfaces vs tipos

715

¿Cuál es la diferencia entre estas declaraciones (interfaz vs tipo)?

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};
wonea
fuente
44
Encontré este artículo explicando las diferencias - medium.com/@martin_hotell/…
Sandeep GB
1
Diferencia de
Michael Freidgeim

Respuestas:

574

Según la especificación del lenguaje TypeScript :

A diferencia de una declaración de interfaz, que siempre introduce un tipo de objeto con nombre, una declaración de alias de tipo puede introducir un nombre para cualquier tipo de tipo, incluidos los tipos primitivos, de unión e intersección.

La especificación continúa mencionando:

Los tipos de interfaz tienen muchas similitudes con los alias de tipo para los literales de tipo de objeto, pero dado que los tipos de interfaz ofrecen más capacidades, generalmente se prefieren los alias de tipo. Por ejemplo, el tipo de interfaz

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

podría escribirse como el alias de tipo

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

Sin embargo, hacerlo significa que se pierden las siguientes capacidades:

  • Se puede nombrar una interfaz en una cláusula de extensiones o implementaciones, pero un alias de tipo para un literal de tipo de objeto ya no puede ser verdadero desde TS 2.7.
  • Una interfaz puede tener varias declaraciones fusionadas , pero un alias de tipo para un literal de tipo de objeto no puede.
Abedul binario
fuente
109
¿Qué significa "declaraciones combinadas múltiples" en la segunda diferencia?
jrahhali
66
@jrahhali si define la interfaz dos veces, el mecanografiado las fusiona en una sola.
Andrey Fedorov
39
@jrahhali si define el tipo dos veces, el mecanografiado le da un error
Andrey Fedorov
18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco
20
Creo que el primer punto extends or implementsya no es el caso. El tipo puede ser extendido e implementado por a class. Aquí hay un ejemplo typescriptlang.org/play/…
dark_ruby
777

Actualización 2019


Las respuestas actuales y la documentación oficial están desactualizadas. Y para aquellos nuevos en TypeScript, la terminología utilizada no está clara sin ejemplos. A continuación se muestra una lista de las diferencias actualizadas.

1. Objetos / funciones

Ambos se pueden usar para describir la forma de un objeto o una firma de función. Pero la sintaxis difiere.

Interfaz

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

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

Escriba alias

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

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

2. Otros tipos

A diferencia de una interfaz, el alias de tipo también se puede usar para otros tipos, como primitivas, uniones y tuplas.

// primitive
type Name = string;

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

// union
type PartialPoint = PartialPointX | PartialPointY;

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

3. Extender

Ambos se pueden extender, pero de nuevo, la sintaxis difiere. Además, tenga en cuenta que una interfaz y un alias de tipo no son mutuamente excluyentes. Una interfaz puede extender un alias de tipo, y viceversa.

La interfaz extiende la interfaz

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

El alias de tipo extiende el alias de tipo

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

La interfaz extiende el alias de tipo

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

El alias de tipo extiende la interfaz

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

4. Implementa

Una clase puede implementar una interfaz o un alias de tipo, ambos de la misma manera. Sin embargo, tenga en cuenta que una clase y una interfaz se consideran planos estáticos. Por lo tanto, no pueden implementar / extender un alias de tipo que nombre un tipo de unión.

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. Fusión de declaraciones

A diferencia de un alias de tipo, una interfaz se puede definir varias veces y se tratará como una única interfaz (con los miembros de todas las declaraciones fusionadas).

// 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
fuente
99
Si la documentación oficial está desactualizada, ¿dónde se puede confirmar la información que proporcionó?
iX3
6060
Según esta publicación, parece que la única razón para elegir una interfaz en lugar de un alias de tipo es si desea utilizar la función de fusión de declaraciones (punto 5) de las interfaces. Más allá de eso, son equivalentes (y diría que los alias de tipo ofrecen una sintaxis más concisa).
maxedison
17
Siempre uso interfaces para el tipo de objeto literal, de lo contrario usar tipos tiene más sentido, también creo que la fusión de declaraciones no debería usarse de todos modos, en realidad nunca esperaré que se declare una interfaz en otro archivo del proyecto con alguna propiedades adicionales, la verificación de tipo se hizo originalmente para hacerte la vida más fácil y no para hacerte más difícil con estas interfaces ninja: D
Ahmed Kamal
8
¿Entonces, básicamente, es una opción "casi personal" para lo que realmente nos sentimos cómodos usando? Aparte de una razón, ¿puedes usar typeo interface? Todavía estoy confundido sobre cuándo debo usar uno u otro.
Joseph Briggs
77
¿Podría alguien motivarme por qué querría fusionar la interfaz? Eso me parece potencialmente confuso. ¿Por qué querría difundir la definición de su interfaz en diferentes bloques?
Vanquish46
95

A partir de TypeScript 3.2 (noviembre de 2018), lo siguiente es cierto:

ingrese la descripción de la imagen aquí

Karol Majewski
fuente
99
¿Podría proporcionar más información sobre cómo se generó la tabla / imagen que proporcionó? por ejemplo, código fuente o enlaces a la documentación
iX3
23
Sí, me refería a la fuente del contenido, no a su presentación.
iX3
3
No creo que una clase pueda extender un tipo o una interfaz, y realmente no puedo ver por qué querrías hacerlo.
Dan King,
77
Evite publicar imágenes de texto, en su lugar incluya el texto real directamente en su publicación. Las imágenes de texto no se pueden analizar ni buscar fácilmente, y los usuarios con discapacidad visual no pueden acceder a ellas.
Andrew Marshall
2
Esta tabla carece de fuentes para respaldar su contenido y no confiaría en ella. Por ejemplo, puede definir tipos recursivos typecon ciertas limitaciones (y a partir de TypeScript 3.7 estas limitaciones también se han eliminado). Las interfaces pueden extender tipos. Las clases pueden implementar tipos. Además, presentar datos como una captura de pantalla de una tabla hace que sea completamente inaccesible para las personas con problemas de visión.
Michał Miszczyszyn
5

Ejemplos con tipos:

// crea una estructura de árbol para un objeto. No puede hacer lo mismo con la interfaz debido a la falta de intersección (&)

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

// escriba para restringir una variable para asignar solo unos pocos valores. Las interfaces no tienen unión (|)

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

// gracias a los tipos, puede declarar tipos no anulables gracias a un mecanismo condicional.

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

Ejemplos con interfaz:

// puedes usar la interfaz para OOP y usar 'implementos' para definir el esqueleto de objeto / clase

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)
    }
}

// puedes extender interfaces con otras interfaces

    interface IMyObject {
        label: string,
    }

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

la documentación ha explicado

  • Una diferencia es que las interfaces crean un nuevo nombre que se usa en todas partes. Los alias de tipo no crean un nuevo nombre; por ejemplo, los mensajes de error no usarán el nombre de alias. En versiones anteriores de TypeScript, los alias de tipo no podían ampliarse ni implementarse (ni podían ampliar / implementar otros tipos). A partir de la versión 2.7, los alias de tipo pueden ampliarse creando un nuevo tipo de intersección
  • Por otro lado, si no puede expresar alguna forma con una interfaz y necesita usar un tipo de unión o tupla, los alias de tipo suelen ser el camino a seguir.

Interfaces versus alias de tipo

Liu Lei
fuente