Доброе утро, TypeScript: как начинается день разработчика
Представьте: 9:00 утра. Вы открываете ноутбук, завариваете кофе и видите в Telegram сообщение от коллеги: «Слушай, я вчера написал функцию, но TypeScript ругается на тип unknown. Помоги!». Знакомо? Добро пожаловать в типичный рабочий день TypeScript разработчика. Это не просто написание кода — это искусство балансировать между строгой типизацией, дедлайнами и бесконечными рефакторингами.
В этой статье я покажу вам реальный день из жизни разработчика на TypeScript: с утреннего стендапа до вечернего коммита. Вы увидите живые примеры кода, типичные проблемы и способы их решения. Поехали!
Утро: стендап и код-ревью
9:30 — Daily standup
Короткая встреча с командой. Вы говорите: «Вчера закончил модуль авторизации, сегодня планирую разобраться с типизацией ответов от API». И тут же слышите: «А не хочешь вынести интерфейсы в отдельный файл? У нас же code style». TypeScript разработчик всегда думает на шаг вперёд: интерфейсы, дженерики, utility types.
Пример: вы обсуждаете типизацию ответа от сервера. Вместо того чтобы писать any, вы предлагаете:
interface ApiResponse<T> {
data: T;
error: string | null;
status: number;
}
type User = {
id: string;
name: string;
email: string;
};
// Использование
const response: ApiResponse<User[]> = await fetchUsers();
Коллеги кивают — это правильный подход. TypeScript разработчик знает: хорошая типизация — половина успеха.
10:00 — Код-ревью: находим баги до того, как они найдут нас
После стендапа вы открываете Pull Request от джуниора. Он написал функцию для валидации email. Код работает, но TypeScript подсказывает: Type 'string | undefined' is not assignable to type 'string'. Вы оставляете комментарий:
// ❌ Проблема: не обработаны null/undefined
function validateEmail(input: string | null | undefined): boolean {
if (!input) return false;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(input);
}
// ✅ Решение: используем guards и optional chaining
function validateEmail(input: unknown): input is string {
return typeof input === 'string' &&
input.length > 0 &&
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(input);
}
Вы объясняете: TypeScript разработчик всегда думает о краевых случаях. Типизация — это не про ограничения, а про безопасность.
Середина дня: написание кода и работа с дженериками
11:30 — Главная задача дня: рефакторинг легаси
Вы берётесь за старый JavaScript-модуль, который нужно переписать на TypeScript. Там есть функция, которая принимает «что угодно» и возвращает «что угодно». Классика:
// 🚫 Старый JS-код
function processData(data) {
if (data.type === 'user') {
return { id: data.id, name: data.name };
}
if (data.type === 'order') {
return { orderId: data.id, total: data.total };
}
return null;
}
Вы превращаете это в строго типизированный код с помощью discriminated unions:
// ✅ TypeScript-версия
type UserData = { type: 'user'; id: string; name: string };
type OrderData = { type: 'order'; id: string; total: number };
type InputData = UserData | OrderData;
type ProcessedResult<T> = T extends UserData
? { id: string; name: string }
: T extends OrderData
? { orderId: string; total: number }
: never;
function processData<T extends InputData>(data: T): ProcessedResult<T> {
if (data.type === 'user') {
return { id: data.id, name: data.name } as ProcessedResult<T>;
}
return { orderId: data.id, total: data.total } as ProcessedResult<T>;
}
Теперь TypeScript сам выводит правильный тип результата в зависимости от входных данных. Коллега заглядывает через плечо и говорит: «Круто, я бы так не смог». Вы улыбаетесь — это обычный рабочий день TypeScript разработчика.
13:00 — Обед и мысли о типизации
За обедом вы листаете Telegram-каналы по TypeScript. Видите пост про satisfies operator и думаете: «Надо будет применить в проекте». Даже в перерыве вы остаётесь в контексте — TypeScript разработчик живёт в мире типов.
После обеда: дебаггинг и работа с API
14:00 — Интеграция с внешним API
Вы подключаете новый сервис. Документация говорит: «Ответ может быть таким или таким, а иногда пустым». Без TypeScript это был бы хаос. Вы создаёте точную модель данных:
// Типизация нестабильного API
type ExternalApiResponse =
| { status: 'success'; data: Record<string, unknown> }
| { status: 'error'; message: string }
| { status: 'pending'; estimatedTime: number };
async function fetchExternalData(): Promise<ExternalApiResponse> {
const response = await fetch('https://api.example.com/data');
const raw: unknown = await response.json();
// Проверка структуры
if (typeof raw === 'object' && raw !== null && 'status' in raw) {
return raw as ExternalApiResponse;
}
throw new Error('Invalid API response format');
}
Вы используете unknown вместо any — это принципиально. TypeScript разработчик никогда не теряет контроль над данными.
15:30 — Баг-хантинг: таинственный undefined
Приходит баг-репорт: «Кнопка не работает, если пользователь не заполнил поле». Вы открываете код и видите:
function handleSubmit(data: { name?: string }) {
const userName = data.name.toUpperCase(); // 💥 Ошибка!
}
Вы исправляете за 30 секунд:
function handleSubmit(data: { name?: string }) {
const userName = data.name?.toUpperCase() ?? 'Гость';
}
Optional chaining и nullish coalescing — ваши лучшие друзья. Вы добавляете в код правило eslint: @typescript-eslint/no-unnecessary-condition. Теперь такая ошибка не пройдёт код-ревью.
Вечер: подготовка к завтрашнему дню
17:00 — Пишем тесты и документацию
Вы садитесь писать unit-тесты. TypeScript помогает и здесь: тесты становятся самодокументируемыми.
import { describe, it, expect } from 'vitest';
describe('processData', () => {
it('should process user data correctly', () => {
const input: UserData = { type: 'user', id: '123', name: 'Alice' };