Хотите заказать веб-сайт? Связаться с нами

Тип any и директива @ts-ignore в TypeScript

TypeScript создан для того, чтобы находить ошибки ещё до запуска кода, но иногда система типов мешает работать так быстро, как хотелось бы. Для таких ситуаций существуют два предохранительных клапана — тип any и директива @ts-ignore. В этом уроке разберёмся, как они работают, чем отличаются друг от друга и почему злоупотреблять ими опасно.

Тип any и директива @ts-ignore в TypeScript

Что такое тип any

Тип any — это способ сказать компилятору «дальше не проверяй». Переменная с типом any может хранить строку, число, объект или функцию, и TypeScript не будет жаловаться ни на присваивание, ни на обращение к любым свойствам и методам. По сути, any временно отключает всю пользу от системы типов для конкретного значения.

Чаще всего any появляется в трёх ситуациях: при постепенной миграции проекта с JavaScript на TypeScript, когда ещё не на все переменные расставлены аннотации; при работе со сторонним кодом или JSON-ответом сервера, структура которого заранее не описана; и в черновых набросках, когда важнее быстро проверить идею, чем сразу продумать типы. Ни один из этих случаев не означает, что any — это плохая практика сама по себе, но каждый из них подразумевает, что any должен быть временным решением, а не постоянным.

let userInput: any;
 
userInput = "hello";
userInput = 42;
userInput = { role: "admin" };
 
// Компилятор промолчит, хотя у числа нет метода toUpperCase
userInput = 42;
console.log(userInput.toUpperCase());

Почему any называют дырой в системе типов

Главная опасность any не в том, что он разрешает одну «неаккуратную» переменную, а в том, что он заразен: как только значение с типом any попадает в другую переменную, передаётся в функцию или сохраняется в объект, все они тоже теряют проверку типов, даже если формально объявлены с конкретным типом. Ошибка не появляется в момент написания кода — она просто переносится дальше по цепочке и всплывает в рантайме, когда её уже сложнее найти.

function parseConfig(raw: any) {
  return raw;
}
 
const config = parseConfig('{"port": 3000}');
// config имеет тип any, хотя по смыслу это объект
config.port.toFixed(2); // TypeScript не предупредит, а в рантайме будет ошибка

Вместо any в большинстве случаев лучше использовать unknown. Этот тип тоже принимает любое значение, но не позволяет обращаться к его свойствам или методам, пока вы явно не сузите тип с помощью проверки или type guard. Так компилятор продолжает страховать вас даже там, где точный тип заранее неизвестен.

Директива @ts-ignore

В отличие от any, который является типом, @ts-ignore — это специальный комментарий-директива. Он ставится строкой выше проблемного кода и просит компилятор полностью пропустить проверку следующей строки, независимо от того, какая именно ошибка там возникает. Директиву обычно используют точечно: когда вы точно знаете, что предупреждение компилятора ложное, или когда нужно временно обойти проблему при миграции старого кода, не переписывая его целиком прямо сейчас.

interface Event {
  id: string;
  title: string;
}
 
function getEvent(): Event {
  // @ts-ignore
  return null;
}

У такого подхода есть цена. Директива @ts-ignore отключает проверку строки целиком, а не только ту ошибку, из-за которой её поставили. Если позже в этой же строке появится другая, уже настоящая ошибка, компилятор о ней тоже промолчит. Кроме того, такие комментарии легко забыть удалить, и они годами живут в проекте, скрывая проблемы, которые давно можно было бы исправить нормальными типами.

Чем @ts-ignore отличается от @ts-expect-error

Более безопасная альтернатива — директива @ts-expect-error. Она работает похоже, но с одним важным отличием: если на следующей строке ошибки на самом деле нет, сама директива становится ошибкой с текстом о неиспользуемом подавлении. Это значит, что как только вы исправите код и ошибка исчезнет, TypeScript сам напомнит убрать директиву. Такой вариант особенно удобен в тестах и в незавершённом коде, где ошибка ожидаема лишь временно.

// @ts-expect-error — функция ещё не реализована, ошибка ожидаема
const total = calculateTotal();

Когда использовать any и @ts-ignore, а когда лучше избегать

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

Инструмент Когда применять
any Временная заглушка при миграции с JavaScript или работе с необследованным сторонним кодом
unknown Значение неизвестного типа, которое нужно безопасно сузить перед использованием
@ts-ignore Разовое подавление конкретной строки, если ошибка точно ложная и решение временное
@ts-expect-error Ожидаемая ошибка в тестах или незавершённом коде, которая должна исчезнуть после исправления

Чтобы any и @ts-ignore не превратились в привычку, полезно придерживаться нескольких простых правил.

  1. Ограничивайте область действия any одной переменной или параметром, а не целым модулем
  2. Не выносите функции с any в публичный API компонентов или библиотек
  3. Сопровождайте @ts-ignore коротким комментарием с причиной и, если возможно, ссылкой на задачу
  4. Периодически ищите any и @ts-ignore по проекту и заменяйте их точными типами

Включите правило @typescript-eslint/no-explicit-any в конфигурацию ESLint. Оно не запрещает any полностью, но подсвечивает каждое такое место в редакторе, поэтому забытые заглушки не потеряются в большом проекте и всегда останутся на виду у команды.

Итоги

Тип any и директива @ts-ignore — это не признак плохого TypeScript, а осознанный компромисс, к которому стоит прибегать редко и с пониманием последствий. Там, где это возможно, безопаснее заменить any на unknown, а @ts-ignore — на @ts-expect-error, чтобы компилятор продолжал помогать вам даже в сложных местах.

В следующем уроке мы сделаем шаг назад и повторим все ключевые темы курса — от аннотаций и union-типов до интерфейсов, generics и настроек компилятора.

Теги: