Продолжаем серию коротких статей и сегодня раз и навсегда разберемся с 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 и теперь рьяно следим за тем, чтобы не случился рецидив. Чего и вам желаю.







