TypeScript: interfaces versus tipos

715

Qual é a diferença entre essas instruções (interface x tipo)?

interface X {
    a: number
    b: string
}

type X = {
    a: number
    b: string
};
wonea
fonte
4
Encontrado este artigo explicando as diferenças - medium.com/@martin_hotell/…
Sandeep GB
1
Pergunta semelhante diferença entre tipo e classe
Michael Freidgeim

Respostas:

574

Conforme a especificação da linguagem TypeScript :

Diferentemente de uma declaração de interface, que sempre introduz um tipo de objeto nomeado, uma declaração de alias de tipo pode introduzir um nome para qualquer tipo de tipo, incluindo tipos primitivos, de união e de interseção.

A especificação continua a mencionar:

Os tipos de interface têm muitas semelhanças com aliases de tipo para literais de tipo de objeto, mas, como os tipos de interface oferecem mais recursos, eles geralmente são preferidos aos aliases de tipo. Por exemplo, o tipo de interface

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

poderia ser escrito como o alias do tipo

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

No entanto, isso significa que os seguintes recursos são perdidos:

  • Uma interface pode ser nomeada em uma cláusula de extensão ou implementação, mas um alias de tipo para um literal de tipo de objeto não pode mais ser verdadeiro desde o TS 2.7.
  • Uma interface pode ter várias declarações mescladas , mas um alias de tipo para um literal de tipo de objeto não pode.
Árvore de vidoeiro binário
fonte
109
O que significa "múltiplas declarações mescladas" na segunda diferença?
jrahhali
66
@jrahhali Se você definir a interface duas vezes, o texto datilografado as mescla em um.
Andrey Fedorov
39
@jrahhali se definir digite duas vezes, typescript lhe dá erro
Andrey Fedorov
18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco
20
Eu acredito que o primeiro ponto extends or implementsnão é mais o caso. O tipo pode ser estendido e implementado por a class. Aqui está um exemplo typescriptlang.org/play/…
dark_ruby
777

Atualização de 2019


As respostas atuais e a documentação oficial estão desatualizadas. E para os iniciantes no TypeScript, a terminologia usada não é clara sem exemplos. Abaixo está uma lista de diferenças atualizadas.

1. Objetos / Funções

Ambos podem ser usados ​​para descrever a forma de um objeto ou uma assinatura de função. Mas a sintaxe é diferente.

Interface

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

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

Alias ​​do tipo

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

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

2. Outros tipos

Ao contrário de uma interface, o alias de tipo também pode ser usado para outros tipos, como primitivos, uniões e 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. Estender

Ambos podem ser estendidos, mas, novamente, a sintaxe é diferente. Além disso, observe que um alias de interface e tipo não é mutuamente exclusivo. Uma interface pode estender um alias de tipo e vice-versa.

Interface estende interface

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

Alias ​​de tipo estende alias de tipo

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

A interface estende o alias de tipo

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

O alias de tipo estende a interface

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

4. Implementos

Uma classe pode implementar uma interface ou alias de tipo, ambos da mesma maneira exata. Observe, no entanto, que uma classe e uma interface são consideradas projetos estáticos. Portanto, eles não podem implementar / estender um alias de tipo que nomeie um tipo de união.

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. Fusão de declaração

Ao contrário de um alias de tipo, uma interface pode ser definida várias vezes e será tratada como uma única interface (com membros de todas as declarações sendo mescladas).

// 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
fonte
9
Se a documentação oficial estiver desatualizada, onde as informações que você forneceu podem ser confirmadas?
iX3 23/01/19
60
Com base neste post, parece que o único motivo para escolher uma interface em vez de um alias de tipo é se você deseja usar o recurso de mesclagem de declarações (ponto 5) das interfaces. Além disso, eles são equivalentes (e eu diria que os aliases de tipo oferecem sintaxe mais concisa).
Maxedison 9/02/19
17
Eu sempre uso interfaces para o tipo de objeto literal, caso contrário, usar tipos faz mais sentido, também acho que a mesclagem de declaração não deve ser usada de maneira alguma, na verdade, nunca esperarei que uma interface esteja sendo declarada em outro arquivo do projeto com alguma propriedades extras, verificação de tipo é feita originalmente para tornar sua vida mais fácil para não tornar mais difícil com este ninja-like interfaces: D
Ahmed Kamal
8
Então, basicamente, é uma escolha "quase pessoal" para o que realmente nos sentimos à vontade em usar? Além de um motivo, você pode simplesmente usar typeou interface? Ainda estou confuso sobre quando devo usar um ou outro.
Joseph Briggs
7
Alguém poderia fornecer alguma motivação para o motivo de você querer mesclar a interface? Isso parece potencialmente confuso para mim. Por que você gostaria de espalhar a definição da sua interface entre diferentes blocos?
usar o seguinte
95

A partir do TypeScript 3.2 (novembro de 2018), o seguinte é verdadeiro:

insira a descrição da imagem aqui

Karol Majewski
fonte
9
Você poderia fornecer mais informações sobre como a tabela / imagem que você forneceu foi gerada? por exemplo, código-fonte ou links para documentação
iX3 23/01/19
23
sim, eu quis dizer a fonte do conteúdo, não a sua apresentação.
iX3 24/01/19
3
Eu não acredito que uma classe possa estender um tipo ou uma interface, e eu realmente não consigo entender por que você gostaria?
Dan King
7
Evite postar imagens de texto; em vez disso, inclua o texto real diretamente em sua postagem. Imagens de texto não são facilmente analisáveis ​​ou pesquisáveis ​​e não são acessíveis a usuários com deficiência visual.
Andrew Marshall
2
Esta tabela carece de fontes para suportar seu conteúdo e eu não confiaria nela. Por exemplo, você pode definir tipos recursivos usando typedeterminadas limitações (e a partir do TypeScript 3.7 essas limitações também desapareceram). As interfaces podem estender tipos. Classes podem implementar tipos. Além disso, a apresentação de dados como captura de tela de uma tabela torna completamente inacessível para pessoas com visão prejudicada.
Michał Miszczyszyn 17/09/19
5

Exemplos com tipos:

// cria uma estrutura em árvore para um objeto. Você não pode fazer o mesmo com a interface devido à falta de interseção (&)

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

// digite para restringir uma variável para atribuir apenas alguns valores. As interfaces não têm união (|)

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

// graças aos tipos, você pode declarar o tipo NonNullable graças a um mecanismo condicional.

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

Exemplos com interface:

// você pode usar a interface para OOP e 'implementa' para definir o esqueleto de objeto / 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)
    }
}

// você pode estender interfaces com outras interfaces

    interface IMyObject {
        label: string,
    }

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

a documentação explicou

  • Uma diferença é que as interfaces criam um novo nome que é usado em qualquer lugar. Os aliases de tipo não criam um novo nome - por exemplo, as mensagens de erro não usam o nome alternativo. Nas versões anteriores do TypeScript, os aliases de tipo não podiam ser estendidos ou implementados (nem estender / implementar outros tipos). A partir da versão 2.7, os aliases de tipo podem ser estendidos criando um novo tipo de interseção
  • Por outro lado, se você não pode expressar alguma forma com uma interface e precisar usar um tipo de união ou de tupla, os aliases de tipo geralmente são o caminho a percorrer.

Interfaces x aliases de tipo

Liu Lei
fonte