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

Какая иерархия типов в TypeScript?

2.0 Middle🔥 181 комментариев
#JavaScript Core#TypeScript

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

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

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

Иерархия типов в TypeScript

Иерархия типов в TypeScript представляет собой систему отношений между типами, которая определяет их совместимость и взаимозаменяемость. Понимание этой иерархии критически важно для написания типобезопасного кода и предотвращения распространенных ошибок.

Базовые принципы иерархии

TypeScript использует структурную типизацию (structural typing), в отличие от номинальной (nominal), что означает: совместимость типов определяется их структурой, а не явным объявлением. Два типа считаются совместимыми, если они имеют одинаковую форму, даже если их имена разные.

interface Point {
  x: number;
  y: number;
}

interface Vector2D {
  x: number;
  y: number;
}

// Структурная совместимость: Point и Vector2D взаимозаменяемы
const point: Point = { x: 1, y: 2 };
const vector: Vector2D = point; // OK, структуры идентичны

Вершина иерархии: тип any

Тип any находится на самом верху иерархии — он совместим со всеми типами и может принимать любое значение. Однако его использование противоречит философии TypeScript, поскольку отключает проверку типов:

let value: any = "строка";
value = 42;           // OK
value = [1, 2, 3];    // OK
value.toFixed();      // Компиляция проходит, но будет ошибка времени выполнения

unknown — типобезопасная альтернатива any

Тип unknown также находится на вершине иерархии, но требует явного сужения типа перед использованием, что делает его типобезопасным:

let value: unknown = "строка";

// value.toUpperCase(); // Ошибка: тип unknown

if (typeof value === "string") {
  console.log(value.toUpperCase()); // OK после сужения
}

never — основание иерархии

Тип never находится в самом низу иерархии — он представляет значения, которые никогда не могут возникнуть. Его можно присвоить любому типу, но ни один тип нельзя присвоить ему:

function error(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {}
}

// never совместим со всеми типами
const a: string = error("Ошибка"); // OK

Примитивные типы и их отношения

Примитивные типы (string, number, boolean, symbol, null, undefined) образуют отдельные ветви иерархии. Интересные особенности:

  • Литеральные типы (literal types) являются подтипами соответствующих примитивных типов
  • null и undefined в строгом режиме (strictNullChecks) несовместимы с другими типами
let name: string = "Иван";
let specificName: "Иван" = "Иван"; // Литеральный тип

name = specificName; // OK: "Иван" можно присвоить string
// specificName = name; // Ошибка: string нельзя присвоить "Иван"

Объектные типы и их иерархия

Для объектных типов действует правило ковариантности (covariance) по свойству: тип A совместим с типом B, если все свойства A совместимы с соответствующими свойствами B.

interface Animal {
  name: string;
}

interface Dog extends Animal {
  breed: string;
}

let animal: Animal = { name: "Животное" };
let dog: Dog = { name: "Бобик", breed: "Дворняга" };

animal = dog; // OK: Dog имеет все свойства Animal
// dog = animal; // Ошибка: в animal отсутствует breed

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

Для функций действует контравариантность (contravariance) параметров и ковариантность возвращаемого значения:

type Handler = (x: number) => string;

let handler1: Handler = (n: number) => n.toString();
let handler2: (x: number | string) => string = (x) => x.toString();

// handler1 = handler2; // Ошибка: параметр должен быть контравариантным
handler2 = handler1; // OK: number можно присвоить number | string

Универсальные типы (Generics)

Универсальные типы создают сложные отношения, зависящие от вариативности (variance). TypeScript использует как ковариантность, так и контравариантность в зависимости от контекста:

interface Box<T> {
  value: T;
}

let numberBox: Box<number> = { value: 42 };
let anyBox: Box<any> = { value: "строка" };

// anyBox = numberBox; // Ошибка: ковариантность по T
// numberBox = anyBox; // Ошибка

Полезные выводы для практики

  • Используйте unknown вместо any для повышения типобезопасности
  • Литеральные типы помогают создавать точные контракты API
  • Типы объединения (union types) создают новые ветви в иерархии
  • Типы пересечения (intersection types) комбинируют требования нескольких типов
type Status = "success" | "error"; // Объединение литеральных типов
type Admin = User & Permissions;   // Пересечение типов

Понимание иерархии типов позволяет:

  1. Эффективно использовать систему типов TypeScript
  2. Избегать распространенных ошибок совместимости
  3. Создавать гибкие и безопасные архитектуры
  4. Правильно проектировать интерфейсы и API
Какая иерархия типов в TypeScript? | PrepBro