Топ ошибок начинающих TypeScript разработчиков: от А до Я
TypeScript — это мощный инструмент, который добавляет статическую типизацию в JavaScript, делая код более предсказуемым и безопасным. Однако переход от JS к TS часто сопровождается типичными ошибками, которые могут свести на нет все преимущества строгой типизации. В этой статье мы разберем самые распространенные ошибки начинающих TypeScript разработчиков — от злоупотребления any до неправильной работы с null и undefined. Вы узнаете, как их избежать и писать чистый, надежный код.
1. Злоупотребление типом any
Самая частая ошибка новичков — использовать any везде, где «неохота думать». TypeScript создан для типов, а any отключает проверку полностью.
// ❌ Плохо
function processData(data: any) {
return data.length; // Ошибка во время выполнения, если data — число
}
// ✅ Хорошо
function processData(data: string | unknown[]) {
return data.length; // TypeScript проверит, что data имеет length
}
Совет: Используйте unknown вместо any, если тип действительно неизвестен. Всегда стремитесь к конкретным типам.
2. Игнорирование strictNullChecks
По умолчанию strictNullChecks включен, но многие новички отключают его «для простоты». Это приводит к ошибкам времени выполнения.
// ❌ Плохо (если strictNullChecks: false)
let name: string = null; // Работает, но потом вызовет ошибку
// ✅ Хорошо
let name: string | null = null; // Явно указываем возможность null
if (name !== null) {
console.log(name.toUpperCase());
}
Совет: Никогда не отключайте strictNullChecks. Используйте Optional Chaining (?.) и Nullish Coalescing (??) для безопасной работы с null/undefined.
3. Неправильное использование типов массивов
Путаница между Array<T> и T[] — это нормально, но главная ошибка — не указывать тип элементов.
// ❌ Плохо
let items = []; // Тип any[]
items.push(1);
items.push("hello"); // Работает, но теряем контроль
// ✅ Хорошо
let items: number[] = []; // Только числа
let strings: Array<string> = []; // Альтернативная запись
Совет: Всегда аннотируйте тип массива, особенно если он пустой при объявлении. Используйте readonly для иммутабельности.
4. Неправильная типизация функций и колбэков
Новички часто забывают типизировать параметры функций или используют Function как тип.
// ❌ Плохо
function fetchData(callback: Function) {
callback("data", 123);
}
fetchData((err: string, data: number) => {}); // Ошибка: ожидается 2 аргумента
// ✅ Хорошо
function fetchData(callback: (err: string | null, data: number) => void) {
callback(null, 123);
}
Совет: Типизируйте параметры и возвращаемое значение явно. Для колбэков используйте стрелочные типы или type/interface.
5. Путаница между interface и type
Многие не понимают разницу и используют их как взаимозаменяемые, что может привести к ошибкам.
// interface — можно объединять (declaration merging)
interface User {
name: string;
}
interface User {
age: number;
} // Работает
// type — нельзя объединять, но можно создавать union/intersection
type Status = "active" | "inactive";
type Admin = User & { role: "admin" };
Совет: Используйте interface для объектов, которые могут расширяться (например, в библиотеках). Используйте type для union-типов, кортежей и сложных композиций.
6. Игнорирование readonly и const для свойств
TypeScript не защищает от мутации объектов по умолчанию. Новички забывают помечать поля как readonly.
// ❌ Плохо
const config = { url: "https://api.example.com" };
config.url = "https://evil.com"; // Работает!
// ✅ Хорошо
interface Config {
readonly url: string;
}
const config: Config = { url: "https://api.example.com" };
// config.url = "new"; // Ошибка: Cannot assign to 'url' because it is a read-only property
Совет: Используйте readonly в интерфейсах для неизменяемых данных. Для массивов — ReadonlyArray<T> или readonly T[].
7. Неправильная работа с enum
TypeScript enum — это не просто набор констант, а объект, который генерирует обратное отображение. Новички часто используют его там, где достаточно union-типа.
// ❌ Плохо — enum генерирует лишний код
enum Direction {
Up = "UP",
Down = "DOWN",
}
function move(d: Direction) {}
// ✅ Хорошо — union-тип проще и безопаснее
type Direction = "UP" | "DOWN";
function move(d: Direction) {}
Совет: Используйте const enum (если нужно) или union-типы. Enum оправдан только когда нужна обратная маппинг (например, для числовых значений).
8. Забывание про never и void
Новички путают void (функция ничего не возвращает) и never (функция никогда не завершается).
// void — функция завершается, но не возвращает значение
function log(message: string): void {
console.log(message);
}
// never — функция никогда не завершается (бросает ошибку или бесконечный цикл)
function throwError(message: string): never {
throw new Error(message);
}
Совет: Используйте void для колбэков, которые ничего не возвращают. never
Блоги
Рекомендаций по книгам
Читайте также
Топ-10 ошибок начинающих Java разработчиков: как их избежать
BDD на Rust: Пишем живой код с Cucumber и Specs
Топ ошибок начинающих PHP разработчиков — часть 4: Работа с данными
Асинхронное программирование в Rust: полное руководство с примерами
Как проверить, ассоциативный массив или нет в PHP: топ ошибок