← Назад к вопросам

В чём разница между interface и type в TypeScript?

2.0 Middle🔥 211 комментариев
#TypeScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Interface vs Type в TypeScript: Полное сравнение

В TypeScript есть два способа определения типов данных: interface и type. На первый взгляд они кажутся взаимозаменяемыми, но у них есть существенные различия, которые влияют на выбор в конкретных ситуациях.

Основное назначение

Interface — предназначен исключительно для определения формы объектов и контрактов для классов. Это более узкоспециализированный инструмент, ориентированный на объектно-ориентированное программирование.

Type — это более универсальный инструмент, который может определять не только объекты, но и примитивы, объединения, пересечения, кортежи и многое другое.

Различия в синтаксисе и возможностях

1. Определение свойств объекта

// Interface
interface User {
  name: string;
  age: number;
  email: string;
}

// Type
type User = {
  name: string;
  age: number;
  email: string;
};

// Оба работают одинаково для объектов
const user: User = {
  name: 'Иван',
  age: 30,
  email: 'ivan@example.com'
};

2. Наследование (extends)

// Interface использует extends
interface Animal {
  name: string;
  age: number;
}

interface Dog extends Animal {
  breed: string;
  bark(): void;
}

const dog: Dog = {
  name: 'Шарик',
  age: 5,
  breed: 'Овчарка',
  bark() { console.log('Гав!'); }
};

// Type использует & (пересечение)
type Animal = {
  name: string;
  age: number;
};

type Dog = Animal & {
  breed: string;
  bark(): void;
};

3. Объединения (Union Types)

Это возможно ТОЛЬКО с type, а не с interface:

// Type позволяет объединять типы
type Status = 'pending' | 'success' | 'error';
type ID = string | number;
type Response = User | Error;

const status: Status = 'pending'; // OK
const id: ID = 123 || 'user-123'; // OK

// Interface НЕЛЬЗЯ использовать для объединений
// interface Status = 'pending' | 'success'; // ОШИБКА!

4. Кортежи и примитивы

Type может определять практически что угодно, interface — только структуры объектов:

// Type работает с примитивами и кортежами
type StringOrNumber = string | number;
type Coordinates = [number, number];
type Callback = (data: string) => void;
type Nullable<T> = T | null;

// Interface не может этого делать
// interface StringOrNumber = string | number; // ОШИБКА!

5. Объединение объявлений (Declaration Merging)

Interface позволяет объединять несколько объявлений одного имени (merging). Type этого не поддерживает:

// Interface: можно расширять в разных местах кода
interface Window {
  myCustomProperty: string;
}

interface Window {
  anotherProperty: number;
}

// Результат: свойства из обоих объявлений объединены
const w: Window = {
  myCustomProperty: 'test',
  anotherProperty: 42
};

// Type: нельзя переобъявлять
type Config = { timeout: number };
type Config = { retries: number }; // ОШИБКА: Duplicate identifier

6. Пересечение типов (Intersection)

// Type: естественно работает с &
type AdminUser = User & { role: 'admin'; permissions: string[] };
type CombinedType = TypeA & TypeB & TypeC;

// Interface: нужно использовать extends
interface AdminUser extends User {
  role: 'admin';
  permissions: string[];
}

7. Условные типы (Conditional Types)

Это возможно только с type:

// Type поддерживает условные типы
type IsString<T> = T extends string ? true : false;

type A = IsString<'hello'>; // true
type B = IsString<123>;      // false

type Flatten<T> = T extends Array<infer U> ? U : T;

type Str = Flatten<string[]>; // string
type Num = Flatten<number>;   // number

// Interface не может быть использован в условных типах

8. Дженерики (Generics)

// Interface с дженериками
interface Container<T> {
  value: T;
  getValue(): T;
}

const stringContainer: Container<string> = {
  value: 'hello',
  getValue() { return this.value; }
};

// Type с дженериками
type Container<T> = {
  value: T;
  getValue(): T;
};

// Оба работают одинаково

Практические примеры

Когда использовать Interface

// 1. Описание структуры объекта в приложении
interface Product {
  id: number;
  name: string;
  price: number;
  inStock: boolean;
}

// 2. Контракт для класса
interface PaymentService {
  processPayment(amount: number): Promise<boolean>;
  refund(transactionId: string): Promise<void>;
}

class StripePayment implements PaymentService {
  async processPayment(amount: number): Promise<boolean> {
    // Реализация
    return true;
  }

  async refund(transactionId: string): Promise<void> {
    // Реализация
  }
}

// 3. Расширение встроенных типов
interface String {
  reverse(): string;
}

Когда использовать Type

// 1. Объединения и условные типы
type UserRole = 'admin' | 'user' | 'guest';
type ApiResponse<T> = { success: true; data: T } | { success: false; error: string };

// 2. Функциональные типы
type Handler = (event: Event) => void;
type Predicate<T> = (item: T) => boolean;

// 3. Утилиты для типов
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

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

// 4. Кортежи и примитивные типы
type Point = [number, number, number];
type Status = 'active' | 'inactive' | 'pending';

Сравнительная таблица

ВозможностьInterfaceType
Описание объектов
Наследование/Расширение✓ (extends)✓ (&)
Объединения (Union)
Примитивные типы
Кортежи
Функциональные типы
Declaration Merging
Условные типы
Mapped Types
Реализация в классах

Рекомендации по использованию

Используй Interface когда:

  • Определяешь структуру объекта, которую будут реализовывать классы
  • Нужна Declaration Merging (расширение существующих типов)
  • Хочешь явно показать контракт для классов

Используй Type когда:

  • Нужны объединения (Union Types)
  • Работаешь с условными или mapped типами
  • Определяешь функциональные типы
  • Нужна большая гибкость

Практический совет

В современных проектах рекомендуется придерживаться одного стиля для консистентности. Многие команды предпочитают использовать type для всех случаев, так как он более универсален. Однако если код использует классы и наследование, interface может быть более понятным.

В чём разница между interface и type в TypeScript? | PrepBro