Топ ошибок начинающих TypeScript разработчиков: от А до Я

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Топ ошибок начинающих 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

Блоги

Рекомендаций по книгам