В этом блоге в основном обсуждаются ключевые отличия interface vs type и рассказывается, как я буду использовать их в своей повседневной работе по разработке программного обеспечения.
Описать форму объекта или сигнатуру функции
Оба могут использоваться для описания формы объекта или сигнатуры функции.
Тем не менее, я в основном использую interface для описания объекта и использую type для описания сигнатуры функции, так как я точно знаю, что это определение функции из arrow function, которую невозможно реализовать в interface.
interface Point {
x: number;
y: number;
}
type SetPoint = (x: number, y: number) => void;
Другой сценарий, в котором я использую интерфейс, — это 「Подписи индексов」. Например, в динамически сгенерированном вводе мы не знаем заранее все имена свойств типа, но знаем форму значений.
interface Input {
[index: string]: string | number;
}
Расширение и типы пересечения
На первый взгляд, расширение и пересечение — это похожие способы объединения типов. Однако принципиальная разница между ними заключается в том, как обрабатываются конфликты.
Для interface, если вы объявите свойство с тем же ключом, оно переопределит свойство в производном интерфейсе. Однако он должен быть совместим с предыдущим, иначе компилятор машинописного текста выдаст ошибку.
// This works pretty well, as it is compatible
interface Converter {
convert: (value: number) => string;
}
interface StringNumberConverter extends Converter {
convert: (value: number | string) => string;
}
// Oops...this will throw an error, as it is incompatible
interface Converter {
convert: (value: number) => string;
}
interface StringNumberConverter extends Converter {
convert: (value: string) => string;
}

Для типа свойства с одним и тем же ключом не обязательно должны быть совместимы. Вы можете объявить все, что угодно.
type Converter = {
convert: (value: number) => string;
}
type StringNumberConverter = Converter & {
convert: (value: string) => string;
}
Еще одно отличие, на которое следует обратить внимание, — это значение, которое они представляют. Когда я использую интерфейс, я хочу, чтобы он обозначал отношения「Родитель-потомок」. В противоположность этому, когда я использую шрифт, он обозначает только отношение 「Композиция」.
// 「Parent-Child」relationship. Cat derives from Animal.
interface Animal {
name: string;
}
interface Cat extends Animal {
color: string;
}
// 「Composition」relationship. Color and Size are two seperate species
type Color = {
name: string
}
type Size = {
size: 'small' | 'medium' | 'large'
}
type ColorSize = Color & Size
Орудия класса
Класс может реализовать интерфейс или псевдоним типа, но не может реализовать тип Union, так как в typescript класс может реализовать только тип объекта или пересечение типов объектов с статически известными членами.
Поэтому в повседневной разработке, если этот тип предназначен для реализации классом, я буду использовать interface вместо type.
type PartialPoint = { x: number; } | { y: number; };
// can not implement a union type
class SomePartialPoint implements PartialPoint {
x = 1;
y = 2;
}
Больше, чем типы объектов
В отличие от интерфейса, псевдоним типа также может использоваться для других типов. Часто используются такие, как тип объединения и кортежи.
type StringNumberPair = [string, number];
function doSomething(stringHash: [string, number]) {
const [inputString, hash] = stringHash;
console.log(inputString); // string
console.log(hash); // number
}
Декларация слияния
interface открыто, а type alias замкнуто внутри себя. Интерфейс может быть определен несколько раз и будет рассматриваться как единый интерфейс с элементами всех объявлений, которые объединяются.
type Bear = {
name: string;
}
// Error:Duplicate Identifier
type Bear = {
age: number;
}
// works pretty well
interface Bear {
name: string;
}
interface Bear {
age: number;
}
const b: Bear = {
name: '',
age: 0
}
Работа с оператором типа typeof
В большинстве случаев, если вы хотите работать с оператором типа typeof, выбирайте type вместо interface.
function f() {
return { x: 10, y: 3 };
}
type P = ReturnType<typeof f>;
/**
** type P = {
x: number;
y: number;
}
**/
Заключение
Когда в следующий раз вы запутаетесь, что использовать, попробуйте эту шпаргалку!
