Яка різниця між цими твердженнями (інтерфейс проти типу)?
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; };
Однак це означає, що такі можливості втрачаються:
Інтерфейс може бути названий в пункті розширення або реалізації, але псевдонім типу для буквального типу об'єкта вже не може бутиістинним, оскільки TS 2.7.- В інтерфейсі може бути кілька об'єднаних оголошень , але псевдонім типу для буквального типу об'єкта не може.
interface Point { x: number; } interface Point { y: number; }
extends or implements
- це вже не так. Тип може бути розширений та реалізований a class
. Ось приклад typescriptlang.org/play / ...
Поточні відповіді та офіційна документація застаріли. І для тих, хто є новим для 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 };
type
або interface
? Я все ще плутаю те, коли мені слід використовувати те чи інше.
type
певні обмеження (а для TypeScript 3.7 ці обмеження також відсутня). Інтерфейси можуть поширювати типи. Класи можуть реалізовувати типи. Більше того, подання даних у вигляді скріншоту таблиці робить його абсолютно недоступним для людей із порушенням зору.
https://www.typescriptlang.org/docs/handbook/advanced-types.html
Одна відмінність полягає в тому, що інтерфейси створюють нове ім’я, яке використовується скрізь. Псевдоніми типу не створюють нове ім'я - наприклад, повідомлення про помилки не використовують ім'я псевдоніма.
// створити структуру дерева для об’єкта. Ви не можете зробити те ж саме з інтерфейсом через відсутність перетину (&)
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
}
Окрім вже наданих блискучих відповідей, помітні відмінності стосуються розширення типів та інтерфейсів. Нещодавно я стикався з кількома випадками, коли інтерфейс не може виконати роботу:
документація пояснила
- Одна відмінність полягає в тому, що інтерфейси створюють нове ім’я, яке використовується скрізь. Псевдоніми типів не створюють нове ім'я - наприклад, у повідомленнях про помилки не буде використовуватися псевдонім name.У старіших версіях TypeScript псевдоніми типів не можна було поширювати чи реалізовувати (а також вони не могли поширювати / впроваджувати інші типи). З версії 2.7 псевдоніми типів можна продовжити, створивши новий тип перетину
- З іншого боку, якщо ви не можете виразити якусь фігуру за допомогою інтерфейсу і вам потрібно використовувати тип з'єднання чи кортеж, зазвичай псевдоніми вводити зазвичай.