Топ ошибок начинающих TypeScript разработчиков: от А до Я
TypeScript — это мощный инструмент, который помогает писать более надежный и предсказуемый код. Однако на старте многие разработчики (особенно те, кто пришел из JavaScript) совершают типичные ошибки. В этой статье мы разберем 10 самых распространенных проблем, с которыми сталкиваются новички, и покажем, как их избежать. Погружаемся в мир TypeScript от А до Я.
1. Чрезмерное использование any
Это, пожалуй, самая популярная ошибка. Когда разработчик не знает, какой тип данных ожидать, он пишет any. Это убивает всю суть TypeScript — статическую типизацию. Вы теряете подсказки редактора и защиту от ошибок во время компиляции.
Плохой пример:
function processData(data: any) {
return data.name.toLowerCase(); // Ошибка появится только в рантайме
}
Как исправить: Используйте более конкретные типы, unknown или дженерики.
function processData(data: { name: string }) {
return data.name.toLowerCase(); // TypeScript проверит это на этапе компиляции
}
Если тип действительно неизвестен, используйте unknown — он заставит вас проверить данные перед использованием.
2. Игнорирование strict-режима
Многие начинающие отключают strict: true в tsconfig.json, чтобы "не было лишних ошибок". Это большая ошибка. Без strict-режима вы теряете проверку на null и undefined, что приводит к Cannot read property of undefined в продакшене.
// Без strict: true — ошибки нет
const name: string = null; // Работает, но потом упадет
// Со strict: true — ошибка компиляции
const name: string = null; // ❌ Type 'null' is not assignable to type 'string'
Совет: Всегда включайте strict: true. Это спасет вас от сотен багов.
3. Неправильное использование типов и интерфейсов
Новички часто путают type и interface, а также используют их там, где это не нужно. Например, создают интерфейс для одной функции, хотя можно просто описать тип прямо в параметре.
Плохой пример:
interface UserData {
name: string;
age: number;
}
function greet(user: UserData) {
console.log(`Hello, ${user.name}`);
}
Это избыточно, если интерфейс используется только один раз.
Как лучше:
function greet(user: { name: string; age: number }) {
console.log(`Hello, ${user.name}`);
}
Используйте interface для объектов, которые расширяются или реализуются классами, а type — для объединений (union) и пересечений (intersection).
4. Забывание про Union Types
Одна из самых мощных фич TypeScript — объединения типов. Новички часто пишут избыточные проверки или используют any, когда можно просто указать несколько допустимых типов.
// Плохо
function getLength(value: any) {
return value.length;
}
// Хорошо
function getLength(value: string | any[]) {
return value.length;
}
TypeScript сам подскажет, какие методы доступны для каждого из типов в объединении.
5. Ошибки с null и undefined
TypeScript строго относится к null и undefined, но новички часто забывают их проверять. Это приводит к ошибкам в рантайме.
function printName(name: string | null) {
console.log(name.toUpperCase()); // ❌ Object is possibly 'null'
}
Как исправить: Используйте защитные проверки (type guards):
function printName(name: string | null) {
if (name !== null) {
console.log(name.toUpperCase()); // ✅ TypeScript знает, что name — это string
}
}
Также полезен оператор ?. (optional chaining) и ?? (nullish coalescing).
6. Игнорирование дженериков (Generics)
Когда нужно написать функцию, работающую с разными типами, новички часто используют any или создают несколько дублирующих функций. Дженерики решают эту проблему элегантно.
// Плохо
function firstElement(arr: any[]) {
return arr[0];
}
// Хорошо
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = firstElement([1, 2, 3]); // Тип: number | undefined
const str = firstElement(['a', 'b']); // Тип: string | undefined
Дженерики сохраняют информацию о типе и делают код переиспользуемым.
7. Неправильная работа с массивами
Путаница между Array<T> и T[] — это нормально, но проблема в том, что новички забывают указывать тип элементов массива.
// Плохо
const items = []; // Тип: never[] — ничего нельзя добавить
items.push('hello'); // ❌ Argument of type 'string' is not assignable to parameter of type 'never'
// Хорошо
const items: string[] = [];
items.push('hello'); // ✅
Всегда аннотируйте тип пустого массива, иначе TypeScript выведет never[].
8. Использование as для каста типов без проверки
Оператор as (type assertion) часто используется, чтобы "заставить" TypeScript поверить, что значение имеет определенный тип. Это опасно, если вы не уверены в данных.
const input = document.getElementById('input') as HTMLInputElement;
// Если элемента нет, input будет null, но TypeScript думает, что это HTMLInputElement
input.value = 'test'; // ❌ Ошибка в рантайме, если элемента нет
Как безопасно:
const input = document.getElementById('input');
if (input instanceof HTMLInputElement) {
input.value = 'test'; // ✅ Безопасно
}
Используйте as только когда вы на 100%