TypeScript: Інтерфейси та типи


Відповіді:


572

Відповідно до специфікації мови TypeScript :

На відміну від декларації інтерфейсу, яка завжди вводить названий тип об'єкта, декларація псевдоніма типу може вводити ім'я для будь-якого типу, включаючи примітивні, об'єднання та перетинні типи.

Специфікація продовжує згадувати:

Типи інтерфейсів мають багато подібності з псевдонімами для літералів типу об'єктів, але оскільки типи інтерфейсів пропонують більше можливостей, вони, як правило, віддають перевагу введення псевдонімів. Наприклад, тип інтерфейсу

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

може бути записаний як псевдонім типу

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

Однак це означає, що такі можливості втрачаються:

  • Інтерфейс може бути названий в пункті розширення або реалізації, але псевдонім типу для буквального типу об'єкта вже не може бути істинним, оскільки TS 2.7.
  • В інтерфейсі може бути кілька об'єднаних оголошень , але псевдонім типу для буквального типу об'єкта не може.

109
Що означає "кілька об'єднаних оголошень" у другій різниці?
jrahhali

66
@jrahhali якщо два рази визначити інтерфейс, машинопис об'єднує їх в один.
Андрій Федоров

39
@jrahhali, якщо ви визначаєте тип два рази, машинопис видає помилку
Андрій Федоров

18
@jrahhaliinterface Point { x: number; } interface Point { y: number; }
Nahuel Greco

20
Я вважаю, що перший момент extends or implements- це вже не так. Тип може бути розширений та реалізований a class. Ось приклад typescriptlang.org/play / ...
dark_ruby

774

Оновлення 2019 року


Поточні відповіді та офіційна документація застаріли. І для тих, хто є новим для TypeScript, використовувана термінологія не зрозуміла без прикладів. Нижче наводиться перелік сучасних відмінностей.

1. Об'єкти / функції

Обидва можуть бути використані для опису форми предмета або підпису функції. Але синтаксис відрізняється.

Інтерфейс

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

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

Введіть псевдонім

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

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

2. Інші типи

На відміну від інтерфейсу, псевдонім типу можна також використовувати для інших типів, таких як примітиви, союзи та кортежі.

// primitive
type Name = string;

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

// union
type PartialPoint = PartialPointX | PartialPointY;

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

3. Розширити

Обидва можна продовжити, але знову ж таки, синтаксис відрізняється. Крім того, зауважте, що псевдонім інтерфейсу та типу не є взаємовиключними. Інтерфейс може поширювати псевдонім типу і навпаки.

Інтерфейс розширює інтерфейс

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

Псевдонім типу розширює псевдонім типу

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

Інтерфейс поширюється псевдонімом типу

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

Тип псевдоніма розширює інтерфейс

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

4. Реалізація

Клас може реалізовувати псевдонім інтерфейсу або типу, обидва однаково точно. Однак зауважте, що клас та інтерфейс вважаються статичними кресленнями. Тому вони не можуть реалізувати / розширити псевдонім типу, який називає тип об'єднання.

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. Декларація злиття

На відміну від псевдоніму типу, інтерфейс можна визначити кілька разів і розглядатиметься як єдиний інтерфейс (з членами всіх декларацій об'єднуються).

// 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 };

9
Якщо офіційна документація застаріла, де можна підтвердити надану вами інформацію?
iX3

59
Виходячи з цього повідомлення, здається, що єдиною причиною вибору інтерфейсу через псевдонім типу є те, якщо ви бажаєте використовувати функцію об'єднання оголошень (точка 5) інтерфейсів. Крім того, вони еквівалентні (і я заперечую, що псевдоніми типів пропонують більш стислий синтаксис).
maxedison

17
Я завжди використовую інтерфейси для буквеного типу об’єкта, інакше використання типів має більше сенсу, також я вважаю, що об'єднання декларацій ні в якому разі не слід використовувати, насправді я ніколи не сподіваюся, що інтерфейс оголошується в іншому файлі проекту з деякими додаткові властивості, перевірка типів виробляється спочатку, щоб полегшити ваше життя, щоб не ускладнити цей інтерфейс, подібний до ніндзя: D
Ахмед Камал

8
Отже, це "майже особистий" вибір того, що нам справді комфортно користуватися? Крім однієї причини, ви можете просто використовувати typeабо interface? Я все ще плутаю те, коли мені слід використовувати те чи інше.
Джозеф Бріггс

7
Невже хтось може надати мотивацію, чому ви хочете об'єднати інтерфейс? Це здається мені потенційно заплутаним. Чому ви хочете поширити визначення свого інтерфейсу на різні блоки?
Vanquish46

95

Станом на TypeScript 3.2 (листопад 2018 р.) Справедливо наступне:

введіть тут опис зображення


9
Чи можете ви надати додаткову інформацію про те, як створювались подані вами таблиці / зображення? наприклад вихідний код або посилання на документацію
iX3

23
так, я мав на увазі джерело вмісту, а не його викладення.
iX3

3
Я не вірю, що клас може поширювати або тип, або інтерфейс, і я не можу реально зрозуміти, чому б ви хотіли ??
Дан Кінг

7
Уникайте публікацій тексту тексту, натомість включайте фактичний текст безпосередньо у свою публікацію. Зображення тексту не легко піддаються аналізу чи пошуку та не доступні користувачам із вадами зору.
Ендрю Маршалл

2
У цій таблиці немає джерел, які б підтримували її вміст, і я б не покладався на нього. Наприклад, ви можете визначити рекурсивні типи, використовуючи typeпевні обмеження (а для TypeScript 3.7 ці обмеження також відсутня). Інтерфейси можуть поширювати типи. Класи можуть реалізовувати типи. Більше того, подання даних у вигляді скріншоту таблиці робить його абсолютно недоступним для людей із порушенням зору.
Michał Miszczyszyn

22

https://www.typescriptlang.org/docs/handbook/advanced-types.html

Одна відмінність полягає в тому, що інтерфейси створюють нове ім’я, яке використовується скрізь. Псевдоніми типу не створюють нове ім'я - наприклад, повідомлення про помилки не використовують ім'я псевдоніма.


30
Це тепер застаріло і більше не відповідає дійсності з TypeScript 2.1. Подивитися. medium.com/@martin_hotell/…
demisx

5

Приклади з типами:

// створити структуру дерева для об’єкта. Ви не можете зробити те ж саме з інтерфейсом через відсутність перетину (&)

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

// type, щоб обмежити змінній призначити лише кілька значень. Інтерфейси не мають з'єднання (|)

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

// завдяки типам ви можете оголосити тип NonNullable завдяки умовному механізму.

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

Приклади з інтерфейсом:

// Ви можете використовувати інтерфейс для OOP та використовувати "tools" для визначення скелета об'єкта / класу

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

// Ви можете розширювати інтерфейси з іншими інтерфейсами

    interface IMyObject {
        label: string,
    }

    interface IMyObjectWithSize extends IMyObject{
        size?: number
    }

1

Окрім вже наданих блискучих відповідей, помітні відмінності стосуються розширення типів та інтерфейсів. Нещодавно я стикався з кількома випадками, коли інтерфейс не може виконати роботу:

  1. Неможливо розширити тип об'єднання за допомогою інтерфейсу
  2. Неможливо розширити загальний інтерфейс

-2

документація пояснила

  • Одна відмінність полягає в тому, що інтерфейси створюють нове ім’я, яке використовується скрізь. Псевдоніми типів не створюють нове ім'я - наприклад, у повідомленнях про помилки не буде використовуватися псевдонім name.У старіших версіях TypeScript псевдоніми типів не можна було поширювати чи реалізовувати (а також вони не могли поширювати / впроваджувати інші типи). З версії 2.7 псевдоніми типів можна продовжити, створивши новий тип перетину
  • З іншого боку, якщо ви не можете виразити якусь фігуру за допомогою інтерфейсу і вам потрібно використовувати тип з'єднання чи кортеж, зазвичай псевдоніми вводити зазвичай.

Інтерфейси проти типу псевдонімів

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.