any, unknown: различия

any полностью отключает проверку типов и позволяет делать с переменной что угодно, тогда как unknown — безопасная альтернатива: значение можно присвоить чему угодно, но использовать его методы и свойства можно только после narrowing (сужения типа).

Зачем нужно

Понимание разницы между any и unknown критично для написания безопасного кода. any — это «дыра» в системе типов, unknown — безопасная зона для работы с данными неизвестного происхождения (JSON, пользовательский ввод, API).

Где используется

  • any — миграция JS → TS, временные заглушки, работа с нетипизированными библиотеками
  • unknown — обработка внешних данных: JSON.parse, catch блоки ошибок, API-ответы
  • Оба — в generic-коде где тип намеренно не важен (но лучше unknown)

Основной контент

Сравнение поведения

// any — TypeScript «закрывает глаза»
let a: any = "hello";
a.toUpperCase();       // OK (компилятор)
a.nonExistentMethod; // OK (компилятор) — упадёт в рантайме!
a = 42;                // OK
const b: string = a;  // OK — any совместим с любым типом

// unknown — TypeScript требует проверки
let u: unknown = "hello";
// u.toUpperCase();       // Error: Object is of type 'unknown'
// u.nonExistentMethod; // Error
// const c: string = u;  // Error — unknown не совместим с string

// Нужно сначала сузить тип:
if (typeof u === "string") {
  u.toUpperCase(); // OK — u: string здесь
}

Присваивание: симметрия vs асимметрия

// any принимает всё и совместим со всем
let a: any;
a = "string";    // OK
a = 42;          // OK
a = null;        // OK

const s: string = a;  // OK — any → string
const n: number = a;  // OK — any → number

// unknown принимает всё, но сам не совместим с конкретными типами
let u: unknown;
u = "string";  // OK
u = 42;        // OK

// const s: string = u;  // Error — unknown → string без narrowing
const a2: any    = u; // OK — unknown → any
const u2: unknown = u; // OK — unknown → unknown

unknown в catch блоках (TS 4.0+)

// До TS 4.0 — error было any
try {
  JSON.parse("invalid");
} catch (e) {
  // e: any (старый стиль) или unknown (с useUnknownInCatchVariables: true)
  if (e instanceof Error) {
    console.log(e.message); // безопасно
  } else if (typeof e === "string") {
    console.log(e);
  }
}

unknown для парсинга JSON

function parseConfig(json: string): Record<string, unknown> {
  const parsed: unknown = JSON.parse(json);

  if (typeof parsed !== "object" || parsed === null) {
    throw new Error("Config must be an object");
  }

  return parsed as Record<string, unknown>;
}

// Vs небезопасный вариант:
function unsafeParse(json: string): any {
  return JSON.parse(json); // any — проверок нет
}

Когда допустим any

// 1. Временно при миграции JS → TS
function legacyFn(data: any): any {
  return data; // TODO: типизировать
}

// 2. Debug-утилиты
function log(...args: any): void {
  console.log(...args);
}

// 3. Обёртка над нетипизированной библиотекой (временно)
declare const oldLib: any;

Частые ошибки

  • Использовать any вместо unknown для внешних данных — теряется вся защита типов.
  • Не сужать unknown перед использованиемunknown требует typeof, instanceof или type guard.
  • catch (e: any) — в современном TypeScript лучше обрабатывать e как unknown и делать narrowing.
  • any вместо unknown — в generic rest-параметрах часто достаточно unknown.

Альтернативная позиция: никогда any — только unknown

"Unknown — это более строгий тип, чем any. Дело в том, что unknown будет чекаться, а any не будет. В этом и разница."

автор использует any практически никогда. Даже в .d.ts для словарей-словарей:

// Плохо избегает
type Dict1 = Record<string, any>;

// Хорошо — заставляет вызывающего сузить тип
type Dict2 = Record<string, unknown>;

Принцип: any — это дыра в системе типов. Если намеренно отключаешь проверку — выбери unknown и сделай явный narrowing/cast. Это видно в код-ревью.

Связанные темы

Источники

  • 🎓 TypeScript vs JavaScript: как лучше писать типы · 2025-11-08 · YouTube
    • Позиция автора: any не использовать никогда. Только unknown + явное сужение.

Ресурсы