Что не так с any и как мы от него избавились

Frontend

Продолжаем серию коротких статей и сегодня раз и навсегда разберемся с any. Это очень удобная, на первый взгляд, фича TS, которая убивает весь смысл использования этого надмножества. Однако часто соблазн «типизировать» что-то как any велик. И, надеюсь, прочитав эту нарочито короткую заметку, вы раз и навсегда избавитесь от этой вредной привычки.

Что не так с any?

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

// Компонент с any в пропсах
interface UserProfileProps {
  user: any;
  onUpdate: any;
  settings?: any;
}

export const UserProfile = ({ user, onUpdate, settings }: UserProfileProps) => {
  // Не знаем, что есть в user, приходим вручную проверять или гадать
  const userName = user.name;

  user.emial; // Опечатка, но TypeScript не ругается
  user.settings.street; // settings может быть undefined, получим ошибку рантайма

  const handleClick = () => {
    onUpdate(); // Мы не имеем понятия, как использовать функцию
  };

  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={handleClick}>Сохранить</button>
    </div>
  );
};

// Самое страшное - мы не можем нормально использовать компонент, не заглянув в его код
const App = () => {
  return (
    <UserProfile
      user={{ nam: 'John' }} // Ещё одна опечатка, но TS промолчит
      onUpdate={(x) => console.log(x)} // Как будет использована переданная функция, что получит - узнаем в ходе экспериментов
      settings={42} // Зато имеем возможность похулиганить
    />
  );
};

Когда можно применять any?

Коротко — никогда. Или очень и очень редко, в тех случаях когда нам действительно все равно что будет с типизацией. Такие куски кода встречаются, но они довольно редки на моей практике.

Еще один возможный случай — быстрое написание прототипа, но тогда советовал бы обмазать всё комментариями в стиле TODO и FIXME, чтобы потом, когда и если будет время на исправление техдолга, заняться всем этим. Но, по-честному будет тогда сразу писать на родном JS, а TS добавить позже.

На что заменять any?

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

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

Наш случай: типизировать 300+ сущностей и не сойти с ума

Наш проект грешил избыточным использованием any, при этом команда грешила тем, что активно применяла его в описании контрактов API, мотивируя это тем, что мы достоверно не знаем какая структура объекта может прийти от них. Команда слаженная, опытная и знающая проект, поэтому чудом удавалось избежать ошибок в рантайме. Но здесь мне пришлось продавливать решение.

Саботировала рефакторинг созданная задача, которая предполагала «отмену» всех any за один раз и была оценена в 13 сторипойнтов. Она пугала. Никто не хотел ее брать. Да и я, инциатор, не очень то хотел словить выгорание, закопавшись в таком мелком, хоть и важном рефакторинге. Кажется, привычный всем строй победил.

Однако, после того как мы перешли на FSD, я вновь поднял вопрос элиминации any, но прежде чем сделал это, декомпозировал ту крупную задачу. Я проанализировал проект и подсчитал сколько случаев использования этого типа имеется на каждом слайсе. Дальше, чтобы не слишком мельчить с декомпозицией, сгруппировал слайсы «по смыслу» и размеру. В итоге задача распалась на 12 тасок, каждая предполагала распутывание 20-30 случаев использования any.

За 1 предновогодний спринт, когда бизнесовые задачи на паузе, а делать что-то надо, мы втроем без большого психологического и мотивационного урона избавили наш проект этой этой чумы, взвинтили серьезность нарушения правила no-explicit-any до error и теперь рьяно следим за тем, чтобы не случился рецидив. Чего и вам желаю.

Симо Мофин
Симо Мофин

Senior Frontend Developer
Главный по блогу