Урок 08

Type vs Interface

В TypeScript два способа описать форму объекта: type и interface. Оба работают, но есть различия.

Синтаксис

type User = {
    name: string;
    age: number;
};

interface User {
    name: string;
    age: number;
}

Результат одинаковый.

Что умеет только type

Union

type Status = 'idle' | 'loading' | 'success';

interface не умеет union.

Примитивы

type ID = string | number;

Кортежи

type Point = [number, number];

Условные типы

type IsString<T> = T extends string ? true : false;

Маппинг

type Partial<T> = { [K in keyof T]?: T[K] };

Что умеет только interface

Declaration merging

Несколько объявлений с одним именем объединяются:

interface User {
    name: string;
}

interface User {
    age: number;
}

// Итог: { name: string; age: number }

Полезно для расширения библиотечных типов.

Расширение через extends

interface Animal {
    name: string;
}

interface Dog extends Animal {
    breed: string;
}

Type тоже умеет через пересечение:

type Dog = Animal & { breed: string };

Что умеют оба

Расширение

// interface
interface Dog extends Animal {}

// type
type Dog = Animal & {};

Опциональные свойства

type User = { name?: string };
interface User { name?: string; }

readonly

type User = { readonly id: number };
interface User { readonly id: number; }

Индексы

type Dict = { [key: string]: number };
interface Dict { [key: string]: number; }

Разница в производительности

interface чуть быстрее при большом числе расширений. type создаёт новые типы при каждом использовании. На практике разница незаметна.

Ошибки в interface

interface не может выразить некоторые типы:

// Ошибка
interface Status = 'idle' | 'loading';

// Ок
type Status = 'idle' | 'loading';

Сообщения об ошибках

type иногда даёт более понятные ошибки в сложных случаях.

Рекомендации

Используй interface:

  • Для публичных API библиотек
  • Когда нужен declaration merging
  • Для объектов и классов

Используй type:

  • Для union, кортежей, примитивов
  • Для условных и маппированных типов
  • Когда не нужен merging

Согласованность: в проекте придерживайся одного подхода. Большинство современных проектов выбирают type из-за гибкости.

Пример: React-компонент

// type
type ButtonProps = {
    variant: 'primary' | 'secondary';
    onClick: () => void;
};

// interface
interface ButtonProps {
    variant: 'primary' | 'secondary';
    onClick: () => void;
}

В React чаще используют type.

Итоги

  • Оба описывают форму объектов
  • type умеет union, кортежи, условные
  • interface умеет declaration merging
  • Оба умеют extends / пересечение
  • Для проектов — один стиль
  • Современный стандарт — type