В чем разница между этими утверждениями (интерфейс против типа)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
В чем разница между этими утверждениями (интерфейс против типа)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
Согласно спецификации языка TypeScript:
В отличие от объявления интерфейса, которое всегда вводит именованный тип объекта, объявление псевдонима типа может вводить имя для любого типа типа, включая типы примитивов, объединений и пересечений.
Спецификация продолжает упоминать:
Типы интерфейса имеют много общего с псевдонимами типов для литералов типов объектов, но поскольку типы интерфейсов предоставляют больше возможностей, они обычно предпочтительнее псевдонимов типов. Например, тип интерфейса
interface Point { x: number; y: number; }
может быть написано как псевдоним типа
type Point = { x: number; y: number; };
Однако это означает, что следующие возможности будут потеряны:
Интерфейс может быть назван в предложении extends или реализовать, но псевдоним типа для литерала типа объекта больше не может иметь значениеtrue, начиная с TS 2.7.- Интерфейс может иметь несколько объединенных объявлений, но псевдоним типа для литерала типа объекта не может.
Текущие ответы и официальная документация устарели. А для новичков в TypeScript используемая терминология непонятна без примеров. Ниже приведен список актуальных различий.
Оба могут быть использованы для описания формы объекта или сигнатуры функции. Но синтаксис отличается.
интерфейс
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;
В отличие от интерфейса, псевдоним типа может также использоваться для других типов, таких как примитивы, объединения и кортежи.
// primitive
type Name = string;
// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
// union
type PartialPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
Оба могут быть расширены, но, опять же, синтаксис отличается. Кроме того, обратите внимание, что интерфейс и псевдоним типа не являются взаимоисключающими. Интерфейс может расширять псевдоним типа, и наоборот.
Интерфейс расширяет интерфейс
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; };
Класс может реализовывать интерфейс или псевдоним типа, оба одинаково точно. Однако обратите внимание, что класс и интерфейс считаются статическими чертежами. Поэтому они не могут реализовать/расширить псевдоним типа, который называет тип объединения.
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;
}
В отличие от псевдонима типа, интерфейс может быть определен несколько раз и будет рассматриваться как единый интерфейс (с объединением элементов всех объявлений).
// 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 };
Начиная с TypeScript 3.2 (ноябрь 2018 г.), верно следующее:
https://www.typescriptlang.org/docs/handbook/advanced-types.html
Одно отличие состоит в том, что интерфейсы создают новое имя, которое используется повсюду. Типа aliases не создают нового имени - например, сообщения об ошибках не будут использовать псевдоним.
//создаем древовидную структуру для объекта. Вы не можете сделать то же самое с интерфейсом из-за отсутствия пересечения (&)
type Tree<T> = T & { parent: Tree<T> };
//тип, чтобы ограничить переменную, чтобы назначить только несколько значений. Интерфейсы не имеют объединения (|)
type Choise = "A" | "B" | "C";
//благодаря типам вы можете объявить тип NonNullable благодаря условному механизму.
type NonNullable<T> = T extends null | undefined ? never : T;
//вы можете использовать интерфейс для ООП и использовать "инструменты" для определения каркаса объекта/класса
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
}
документация объяснила
- Одно отличие состоит в том, что интерфейсы создают новое имя, которое используется везде. Псевдонимы типов не создают новое имя - например, сообщения об ошибках не будут использовать псевдоним name. В более старых версиях TypeScript псевдонимы типов не могли быть расширены или реализованы (и при этом они не могли расширять/реализовывать другие типы). Начиная с версии 2.7, псевдонимы типов можно расширять, создавая новый тип пересечения
- С другой стороны, если вы не можете выразить какую-либо форму с помощью интерфейса, и вам необходимо использовать тип объединения или кортежа, обычно рекомендуется использовать псевдонимы типов.