Почему TypeScript — must have для современного разработчика?
Если вы открыли эту статью, значит, вы уже знаете, что TypeScript — это не просто «надстройка над JavaScript», а полноценный инструмент, который спасает нервные клетки и продакшн-сервера. На собеседованиях в 2025 году знание TypeScript проверяют почти в 80% вакансий middle+ уровня. И речь не о том, чтобы написать const a: number = 5. Интервьюеры хотят видеть понимание системы типов, дженериков и умение проектировать безопасную архитектуру.
В этой статье мы разберём самые частые вопросы на собеседовании по TypeScript, которые реально задают в топовых компаниях. Вы получите не только теорию, но и примеры кода TypeScript, которые можно сразу использовать в pet-проектах. Поехали!
1. База: типы, интерфейсы и разница между ними
Первый блок вопросов — фундаментальный. Интервьюер хочет убедиться, что вы не путаете type и interface.
Когда использовать type, а когда interface?
Классический вопрос. Запомните простое правило:
- Interface — для объектов, которые можно расширять (declaration merging). Используйте для API, DTO, пропсов компонентов.
- Type — для объединений (
union), пересечений, примитивов и кортежей.
Пример из реального собеседования:
// Interface — расширяем
interface User {
id: number;
name: string;
}
interface AdminUser extends User {
role: 'admin';
}
// Type — объединение
type Status = 'active' | 'inactive' | 'banned';
type ApiResponse<T> = {
data: T;
error?: string;
};
Важно: Никогда не говорите «interface лучше, потому что он быстрее». Разница в производительности микроскопическая. Главное — семантика.
2. Дженерики: как не опозориться на собеседовании
Тема дженериков в TypeScript — любимая мозоль джуниоров. Интервьюеры обожают просить написать функцию, которая принимает массив и возвращает первый элемент с правильным типом.
Пишем дженерик-функцию
function getFirst<T>(arr: T[]): T | undefined {
return arr[0];
}
const num = getFirst([1, 2, 3]); // number
const str = getFirst(['a', 'b']); // string
Теперь усложним — ограничим дженерик с помощью extends:
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 30 };
getProperty(user, 'name'); // OK: string
getProperty(user, 'email'); // Error: 'email' не входит в keyof
Этот паттерн встречается в каждом втором проекте на React + TypeScript. Обязательно потренируйтесь писать дженерики для TypeScript в своих проектах.
3. Utility Types: ваш секретный арсенал
Знание встроенных утилитарных типов — признак профессионализма. Интервьюер может спросить: «Как сделать все поля необязательными?» или «Как выбрать только часть интерфейса?».
Топ-5 utility types, которые нужно знать
Partial<T>— все поля становятся опциональными;Required<T>— все поля обязательны;Pick<T, K>— выбираем только указанные ключи;Omit<T, K>— исключаем указанные ключи;Record<K, V>— создаёт тип объекта с ключами K и значениями V.
Пример, который любят давать на собесе:
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: Date;
}
// Обновляем только часть Todo
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
// Создаём словарь
const todoMap: Record<string, Todo> = {
'1': { title: 'Learn TS', description: '', completed: false, createdAt: new Date() }
};
Попробуйте также Readonly, NonNullable и ReturnType — они часто всплывают в вопросах.
4. Type Guards и сужение типов (Narrowing)
Ещё один блок вопросов: «Как проверить, является ли переменная определённым типом?». Здесь в игру вступают Type Guards.
Пишем собственный type guard
interface Fish {
swim: () => void;
}
interface Bird {
fly: () => void;
}
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined;
}
function move(pet: Fish | Bird) {
if (isFish(pet)) {
pet.swim(); // TS знает, что pet — Fish
} else {
pet.fly(); // TS знает, что pet — Bird
}
}
Обратите внимание на синтаксис pet is Fish. Это и есть type predicate. Без него TypeScript не сможет сузить тип внутри if.
Также изучите typeof, instanceof и in — это базовые guard'ы, которые обязан знать каждый.
5. Mapped Types и Conditional Types
Для senior-позиций вас могут попросить написать свой utility type. Например, сделать все поля массивами.
Mapped Type — делаем все поля опциональными вручную
type MyPartial<T> = {
[P in keyof T]?: T[P];
};
type PartialUser = MyPartial<User>;
// { id?: number; name?: string }
Conditional Type — выбор типа на основе условия
type IsString<T> = T extends string ? 'yes' : 'no';
type A = IsString<string>; // 'yes'
type B = IsString<number>; // 'no'
Это уже продвинутый уровень. Если вы сможете объяснить, как работает infer в условных типах (например, ReturnType), вас точно запомнят.
6. Работа с async/await и типами ошибок
Собеседование по TypeScript редко обходится без вопроса про типизацию асинхронных операций. Попросят написать функцию, которая возвращает Promise с определённым типом.
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error('Failed to fetch user');
}
return response.json(); // TS выведет Promise<User>
}
Хитрый вопрос: «Как типизировать ошибку в