Jaka jest różnica między tymi instrukcjami (interfejs vs typ)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
Jaka jest różnica między tymi instrukcjami (interfejs vs typ)?
interface X {
a: number
b: string
}
type X = {
a: number
b: string
};
Odpowiedzi:
Zgodnie ze specyfikacją języka TypeScript :
W przeciwieństwie do deklaracji interfejsu, która zawsze wprowadza nazwany typ obiektu, deklaracja aliasu typu może wprowadzić nazwę dla dowolnego rodzaju typu, w tym typów pierwotnych, łączących i przecinających się.
Specyfikacja wspomina dalej:
Typy interfejsów mają wiele podobieństw do aliasów typów dla literałów typu obiektowego, ale ponieważ typy interfejsów oferują więcej możliwości, zazwyczaj preferowane są aliasy typów. Na przykład typ interfejsu
interface Point { x: number; y: number; }
można zapisać jako alias typu
type Point = { x: number; y: number; };
Takie postępowanie oznacza jednak utratę następujących możliwości:
Interfejs może być nazwany w klauzuli extends lub implements, ale alias typu dla literału typu obiektu nie możejuż być prawdziwy od TS 2.7.- Interfejs może mieć wiele scalonych deklaracji , ale alias typu dla literału typu obiektu nie może.
interface Point { x: number; } interface Point { y: number; }
extends or implements
już nie ma miejsca. Typ można rozszerzyć i zaimplementować za pomocą class
. Oto przykład typescriptlang.org/play/...
Obecne odpowiedzi i oficjalna dokumentacja są nieaktualne. A dla tych, którzy nie znają TypeScript, zastosowana terminologia nie jest jasna bez przykładów. Poniżej znajduje się lista aktualnych różnic.
Oba mogą być użyte do opisania kształtu obiektu lub sygnatury funkcji. Ale składnia jest różna.
Berło
interface Point {
x: number;
y: number;
}
interface SetPoint {
(x: number, y: number): void;
}
Wpisz alias
type Point = {
x: number;
y: number;
};
type SetPoint = (x: number, y: number) => void;
W przeciwieństwie do interfejsu, alias typu może być również używany dla innych typów, takich jak operacje podstawowe, związki i krotki.
// primitive
type Name = string;
// object
type PartialPointX = { x: number; };
type PartialPointY = { y: number; };
// union
type PartialPoint = PartialPointX | PartialPointY;
// tuple
type Data = [number, string];
Oba można rozszerzyć, ale znowu składnia jest różna. Dodatkowo zauważ, że interfejs i alias typu nie wykluczają się wzajemnie. Interfejs może rozszerzyć alias typu i odwrotnie.
Interfejs rozszerza interfejs
interface PartialPointX { x: number; }
interface Point extends PartialPointX { y: number; }
Alias typu rozszerza alias typu
type PartialPointX = { x: number; };
type Point = PartialPointX & { y: number; };
Interfejs rozszerza alias typu
type PartialPointX = { x: number; };
interface Point extends PartialPointX { y: number; }
Alias typu rozszerza interfejs
interface PartialPointX { x: number; }
type Point = PartialPointX & { y: number; };
Klasa może implementować interfejs lub alias typu, oba w ten sam dokładny sposób. Należy jednak pamiętać, że klasa i interfejs są uważane za statyczne plany. Dlatego nie mogą implementować / rozszerzać aliasu typu, który nazywa typ unii.
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;
}
W przeciwieństwie do aliasu typu interfejs można zdefiniować wiele razy i będzie on traktowany jako pojedynczy interfejs (z scalonymi elementami wszystkich deklaracji).
// 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
lub interface
? Nadal jestem zdezorientowany, kiedy powinienem użyć jednego lub drugiego.
type
pewnych ograniczeń (i od TypeScript 3.7 te ograniczenia również zniknęły). Interfejsy mogą rozszerzać typy. Klasy mogą implementować typy. Co więcej, przedstawienie danych jako zrzut ekranu tabeli powoduje, że są one całkowicie niedostępne dla osób z zaburzeniami widzenia.
https://www.typescriptlang.org/docs/handbook/advanced-types.html
Jedną różnicą jest to, że interfejsy tworzą nową nazwę, która jest używana wszędzie. Aliasy typów nie tworzą nowej nazwy - na przykład komunikaty o błędach nie będą używać nazwy aliasu.
// utwórz strukturę drzewa dla obiektu. Nie możesz zrobić tego samego z interfejsem z powodu braku skrzyżowania (&)
type Tree<T> = T & { parent: Tree<T> };
// wpisz, aby ograniczyć zmienną do przypisania tylko kilku wartości. Interfejsy nie mają związku (|)
type Choise = "A" | "B" | "C";
// dzięki typom możesz zadeklarować typ NonNullable dzięki mechanizmowi warunkowemu.
type NonNullable<T> = T extends null | undefined ? never : T;
// możesz użyć interfejsu dla OOP i użyć „implements” do zdefiniowania szkieletu obiektu / klasy
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)
}
}
// możesz rozszerzyć interfejsy o inne interfejsy
interface IMyObject {
label: string,
}
interface IMyObjectWithSize extends IMyObject{
size?: number
}
Oprócz podanych już genialnych odpowiedzi istnieją zauważalne różnice, jeśli chodzi o rozszerzanie typów w porównaniu z interfejsami. Niedawno natknąłem się na kilka przypadków, w których interfejs nie może wykonać zadania:
dokumentacja wyjaśniła
- Jedną różnicą jest to, że interfejsy tworzą nową nazwę, która jest używana wszędzie. Aliasy typów nie tworzą nowej nazwy - na przykład komunikaty o błędach nie będą używać nazwy aliasu. W starszych wersjach TypeScript aliasy typów nie mogą być rozszerzane ani implementowane (ani nie mogą rozszerzać / implementować innych typów). Począwszy od wersji 2.7, aliasy typów można rozszerzyć, tworząc nowy typ skrzyżowania
- Z drugiej strony, jeśli nie możesz wyrazić jakiegoś kształtu za pomocą interfejsu i musisz użyć typu unii lub krotki, aliasy typu są zazwyczaj dobrym rozwiązaniem.