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

Чаще пользуешься типами или интерфейсами

2.2 Middle🔥 202 комментариев
#Soft Skills и рабочие процессы

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

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

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

Типы vs Интерфейсы в TypeScript

Это частый вопрос на собеседованиях, и ответ показывает понимание различий между type и interface, а также практический опыт в TypeScript. Правильный ответ должен продемонстрировать знание обоих и умение выбрать нужный инструмент.

Мой подход

В большинстве проектов я пользуюсь обоими, но в разных контекстах:

  • Интерфейсы (interface) для определения контрактов компонентов и объектов
  • Типы (type) для альясов и более сложных типовых конструкций

Интерфейсы (interface)

Интерфейсы используются когда нужно определить структуру объекта, особенно для props компонентов и API контрактов:

// Props компонента
interface ButtonProps {
  label: string;
  onClick: (event: React.MouseEvent<HTMLButtonElement>) => void;
  disabled?: boolean;
  variant?: 'primary' | 'secondary';
}

function Button({ label, onClick, disabled = false, variant = 'primary' }: ButtonProps) {
  return (
    <button onClick={onClick} disabled={disabled} className={`btn btn-${variant}`}>
      {label}
    </button>
  );
}

Преимущества интерфейсов:

  1. Слияние (merging) — можно расширять интерфейс в разных местах:
interface User {
  id: string;
  name: string;
}

// Позже в другом файле
interface User {
  email: string;
}

// Результат: User имеет id, name и email
  1. Наследование — очень удобно для иерархий:
interface Entity {
  id: string;
  createdAt: Date;
  updatedAt: Date;
}

interface User extends Entity {
  name: string;
  email: string;
}

interface Post extends Entity {
  title: string;
  content: string;
  authorId: string;
}
  1. Читаемость — четкое определение контракта объекта

Типы (type)

Типы используются когда нужна большая гибкость и составные типы:

// Объединение типов (Union)
type Status = 'loading' | 'success' | 'error' | 'idle';

// Пересечение типов (Intersection)
type UserWithTimestamps = User & Timestamps;

// Условные типы (Conditional)
type Flatten<T> = T extends Array<infer U> ? U : T;

// Типы для функций
type AsyncFunction<T> = () => Promise<T>;

// Альясы для примитивов
type UserId = string & { readonly __brand: 'UserId' };

// Типы с функциональной сигнатурой
type ValidationFunction = (value: string) => boolean;

Преимущества типов:

  1. Гибкость — union, intersection, conditional типы
  2. Кортежи и массивы:
type Response = [status: number, data: unknown, error: Error | null];

const handleResponse: Response = [200, { id: 1 }, null];
  1. Сложные типовые операции:
type Readonly<T> = {
  readonly [K in keyof T]: T[K];
};

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

Правила выбора

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

✅ Определяешь props компонента

interface CardProps {
  title: string;
  children: React.ReactNode;
}

✅ Определяешь API контракт

interface User {
  id: string;
  name: string;
  email: string;
}

✅ Нужна иерархия с наследованием

interface BaseEntity {
  id: string;
}

interface Post extends BaseEntity {
  title: string;
}

✅ Возможно слияние интерфейсов

interface Window {
  myCustomProp?: string;
}

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

✅ Union типы

type Status = 'active' | 'inactive' | 'pending';
type Result = Success | Error;

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

type Awaited<T> = T extends Promise<infer U> ? U : T;

✅ Кортежи

type Coordinates = [x: number, y: number, z?: number];

✅ Альясы для примитивов

type Email = string;
type Age = number;

✅ Функциональные типы

type Handler<T> = (event: T) => void;

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

// components/Question.tsx

// Props компонента - используем interface
interface QuestionProps {
  id: string;
  title: string;
  difficulty: 'easy' | 'medium' | 'hard';
  tags: string[];
  onAnswer: (questionId: string, answer: string) => Promise<void>;
  isLoading?: boolean;
}

// Данные с API - interface
interface Question {
  id: string;
  title: string;
  description: string;
  difficulty: string;
  tags: string[];
  createdAt: Date;
  updatedAt: Date;
}

// Type для status - используем type
type QuestionStatus = 'new' | 'answered' | 'skipped' | 'bookmarked';

// Type для результата API - можем использовать оба
type ApiResponse<T> = {
  data: T | null;
  error: string | null;
  status: 'loading' | 'success' | 'error';
};

function QuestionCard({
  id,
  title,
  difficulty,
  onAnswer,
  isLoading = false,
}: QuestionProps) {
  const [status, setStatus] = React.useState<QuestionStatus>('new');

  const handleSubmit = async (answer: string) => {
    try {
      setStatus('answered');
      await onAnswer(id, answer);
    } catch (error) {
      setStatus('new');
    }
  };

  return (
    <article>
      <h2>{title}</h2>
      <span className={`difficulty difficulty-${difficulty}`}>
        {difficulty}
      </span>
      {/* ... остальной код */}
    </article>
  );
}

Стилевые соглашения

В современном TypeScript сообществе есть тренд:

  1. Используй interface по умолчанию для объектов
  2. Используй type для всего остального

Это согласовано с документацией TypeScript и используется в большинстве крупных проектов (React, Vue, Angular).

// Правильно
interface Props { ... }
type Status = 'active' | 'inactive';
type Handler = () => void;

// Избегай
type Props = { ... }; // Используй interface
interface Status { ... } // Используй type

Производительность

Долгое время верили, что interface быстрее type, но это больше не актуально. TypeScript 5.0+ имеет одинаковую производительность для обоих.

Итоги

В моей практике:

  • interface для структур данных и контрактов (props, API, модели)
  • type для всего остального (union, conditional, functional)
  • Оба используются в проекте, но в разных контекстах
  • Главное — быть консистентным и следовать соглашениям команды
  • Не переживай по производительности — выбирай по удобству
Чаще пользуешься типами или интерфейсами | PrepBro