Технологии

TypeScript для junior frontend-разработчика: что нужно знать для первой работы

Какой TypeScript нужен на первой работе: типы, union и сужение, generics, utility types, типизация React и что об этом спрашивают на собеседовании.

Junior frontend-разработчику для первой работы нужен практический TypeScript: умение типизировать данные из API, пропсы и состояние React-компонентов, события и хуки, уверенное владение union-типами и сужением, базовые generics и utility types, а также привычка работать в строгом режиме. Продвинутые конструкции вроде условных типов на этом уровне почти не спрашивают - важнее писать типизированный код без any и лишних приведений.

TypeScript давно стал стандартом в коммерческой frontend-разработке: он ловит ошибки до запуска кода, служит документацией и помогает безопасно менять большой проект. Ниже - темы в том порядке, в котором их удобно осваивать, и то, как они проявляются на собеседованиях и в реальной работе.

Базовые типы и объекты

Начинать стоит с примитивов - string, number, boolean, null и undefined - и с того, как TypeScript выводит типы сам. Явно указывать тип нужно не везде: у переменной, которой сразу присвоено значение, тип выводится автоматически. Аннотации действительно нужны на границах - в параметрах функций, в пропсах компонентов и там, где данные приходят извне.

Объекты описываются через type или interface. Оба варианта задают форму объекта: какие поля есть, какого они типа, какие из них необязательные (помечаются знаком вопроса), какие только для чтения (readonly). Массивы записываются как User[] или Array<User>, а кортежи фиксируют длину и тип каждого элемента - например, пара из строки и числа.

type или interface

Это один из самых частых вопросов на собеседовании. Interface можно расширять через extends и дополнять повторным объявлением с тем же именем - так, например, расширяют типы сторонних библиотек. Type может описать то, что interface не умеет: union-типы, кортежи, типы, собранные из других с помощью utility types. На практике в проекте выбирают единый стиль, а от кандидата ждут понимания разницы, а не «правильного» ответа.

Union-типы и сужение

Union-тип описывает значение, которое может быть одним из нескольких типов: строка или число, объект пользователя или null, одно из нескольких строковых значений вроде «loading», «success» и «error». Это основа безопасного кода: TypeScript не даст обратиться к полю, которого может не быть, пока вы не проверите, какой именно вариант перед вами.

Такая проверка называется сужением типа. После проверки typeof value === "string" внутри условия TypeScript знает, что значение строковое. Похожим образом работают оператор in, проверка через instanceof, сравнение с null и собственные функции-предикаты, которые возвращают тип вида value is User.

Размеченные объединения

Самый полезный приём для frontend - размеченные объединения: у каждого варианта есть общее поле с уникальным значением, например status. Состояние запроса описывается как объединение трёх вариантов: загрузка без данных, успех с данными и ошибка с сообщением. Проверив status, вы получаете доступ ровно к тем полям, которые есть в этом варианте, и не можете случайно прочитать данные во время загрузки.

Вместе с типом never это даёт проверку полноты: если в switch по status обработаны не все варианты, а в ветке default значение присваивается переменной типа never, компилятор сообщит об ошибке при добавлении нового варианта. Этот приём часто встречается в редьюсерах и обработчиках событий.

any, unknown и приведение типов

any отключает проверку типов: с таким значением можно сделать что угодно, и ошибка всплывёт уже во время работы. unknown тоже означает «тип заранее неизвестен», но требует проверки перед использованием. Поэтому для данных, происхождение которых вы не контролируете, - ответа сервера, содержимого localStorage, результата разбора JSON - безопаснее unknown с последующей проверкой.

Приведение через as говорит компилятору «поверь мне» и не выполняет никакой проверки во время работы. Восклицательный знак после значения утверждает, что оно не null и не undefined. Оба инструмента иногда нужны, но их обилие в коде - сигнал, что типы описаны неточно. На ревью и собеседованиях это замечают сразу.

Generics

Generics позволяют писать функции и типы, которые работают с разными данными, сохраняя связь между входом и выходом. Функция, возвращающая первый элемент массива, с generic-параметром T возвращает именно T, а не any. Тип ответа API можно описать один раз как обёртку с полем data типа T и переиспользовать для пользователей, заказов и товаров.

Ограничения задаются через extends: запись T extends { id: string } означает, что подходит любой тип, у которого есть строковое поле id. С оператором keyof можно написать функцию, которая принимает объект и имя его поля и возвращает значение правильного типа. Эти примеры - классика собеседований, и их стоит уметь написать без подсказок.

Utility types

Встроенные utility types строят новые типы из существующих, чтобы не описывать похожие структуры вручную. Минимальный набор, который нужно знать:

  • Partial и Required - делают все поля необязательными или обязательными; Partial удобен для формы редактирования, где меняется часть полей.
  • Pick и Omit - выбирают или исключают поля; например, тип пользователя без пароля для отображения.
  • Record - объект с заданными ключами и значениями одного типа, например словарь статусов.
  • Readonly - запрещает изменение полей на уровне типов.
  • ReturnType и Parameters - достают тип результата и параметров функции.
  • NonNullable и Awaited - убирают null и undefined или «разворачивают» тип промиса.

На собеседовании могут попросить реализовать Partial или Pick самостоятельно. Для этого нужны сопоставленные типы и keyof - если вы понимаете, как устроены эти две утилиты, остальные читаются без труда.

TypeScript в React

Большая часть повседневной работы junior frontend-разработчика с TypeScript - это типизация React-кода. Здесь важно знать несколько устойчивых шаблонов.

Пропсы и children

Пропсы описываются отдельным типом, а необязательные помечаются знаком вопроса и получают значение по умолчанию при деструктуризации. Для содержимого компонента используется тип React.ReactNode. Если компонент оборачивает стандартный элемент, например кнопку, удобно расширить его атрибуты через ComponentProps<"button"> - тогда он примет все стандартные свойства без ручного перечисления.

Состояние и хуки

useState обычно выводит тип из начального значения, но если начальное значение null, а позже там появится объект, тип указывается явно: useState<User | null>(null). useRef для DOM-элемента типизируется как ссылка на конкретный элемент с начальным null. Для useReducer действия удобно описывать размеченным объединением - тогда в каждой ветке редьюсера доступны только поля нужного действия.

События и формы

Обработчики событий типизируются через типы React: изменение поля ввода - React.ChangeEvent<HTMLInputElement>, отправка формы - React.FormEvent<HTMLFormElement>. Если обработчик передаётся напрямую в JSX, тип события выводится автоматически; явно указывать его нужно, когда обработчик объявлен отдельно.

Данные из API

Ответ сервера - главное место, где типы расходятся с реальностью. Тип, указанный для результата запроса, ничего не гарантирует во время работы. В учебном проекте достаточно описать типы ответов и аккуратно обрабатывать ошибки, а в реальных командах часто добавляют проверку схемы данных или генерируют типы из описания API. Об этом стоит знать и уметь рассказать.

Литеральные типы и as const

Литеральный тип - это конкретное значение в роли типа: не любая строка, а только «small», «medium» или «large». Объединение таких значений - самый простой и читаемый способ описать варианты размера кнопки, статуса заказа или темы оформления. Компилятор подскажет допустимые значения и не даст передать опечатку.

Запись as const после объекта или массива делает его значения литеральными и доступными только для чтения. Из такого массива можно получить объединение его элементов через индексный доступ к типу - так список вариантов описывается один раз и используется и в коде, и в типах. Многие команды предпочитают этот приём перечислениям enum: он не создаёт дополнительного кода при сборке и лучше сочетается с данными из API.

Типизация собственных хуков

Собственные хуки - хорошая проверка понимания TypeScript. Хук загрузки данных удобно сделать generic: он принимает функцию запроса и возвращает состояние, описанное размеченным объединением с данными типа T. Тогда компонент, использующий хук, получает правильно типизированные данные без приведений.

Если хук возвращает массив из нескольких значений, как useState, стоит добавить as const или явно указать тип кортежа - иначе TypeScript выведет массив из объединения типов, и при деструктуризации каждое значение будет иметь неточный тип. На собеседованиях это иногда дают как задачу: найти, почему у возвращаемых значений «сломались» типы.

Типы сторонних библиотек

Современные библиотеки обычно поставляются со своими типами, а для части старых пакетов типы публикуются отдельно в пространстве @types. Умение открыть файл определений и прочитать сигнатуру функции или хука экономит часы: там видно, какие параметры обязательны, что возвращается и какие generic-параметры можно передать.

Если типов для пакета нет, можно описать минимальное объявление модуля самостоятельно, не прибегая к any для всего пакета. Этот навык редко спрашивают на собеседовании junior, но он быстро пригождается на реальной работе с легаси-кодом.

Строгий режим и настройки

Флаг strict в tsconfig включает набор проверок, среди которых самые важные - strictNullChecks и noImplicitAny. Первый заставляет явно обрабатывать null и undefined, второй запрещает неявный any у параметров. В большинстве современных проектов строгий режим включён, поэтому учебные проекты стоит писать сразу с ним: привычка к нестрогому режиму потом мешает на первой работе.

Полезно знать и оператор satisfies: он проверяет, что значение соответствует типу, но сохраняет более точный выведенный тип. Это удобно для конфигураций и словарей, где важно и проверить форму, и не потерять конкретные ключи.

Что спрашивают на собеседовании

  1. Чем type отличается от interface и когда что выбирать.
  2. Чем any отличается от unknown и почему any опасен.
  3. Что такое union-типы и как работает сужение; пример размеченного объединения.
  4. Как написать generic-функцию с ограничением; пример с keyof.
  5. Какие utility types вы используете и как устроен Partial или Pick.
  6. Как типизировать пропсы, useState с null, useRef и обработчик события.
  7. Что делает strictNullChecks и зачем нужен тип never.

Отвечая, опирайтесь на свой код: «в проекте я описал состояние запроса размеченным объединением, чтобы не читать данные во время загрузки» звучит убедительнее определения из документации. Подборку вопросов по самому React - в статье вопросы на собеседовании по React, а о том, как решать задачи вслух, - в статье лайвкодинг на собеседовании.

Типичные ошибки начинающих

  • any везде, где компилятор ругается. Ошибка не исчезает, а переезжает во время работы программы.
  • Лишние as и восклицательные знаки. Обычно это значит, что тип описан неточно или пропущена проверка.
  • Дублирование типов. Одна и та же структура описана трижды с небольшими отличиями вместо Pick, Omit или Partial.
  • Типы, не совпадающие с данными. Поле описано как обязательное, а сервер иногда его не присылает.
  • Отключённый строгий режим. Проект собирается, но главные проверки не работают.

Как учить TypeScript быстрее

Лучший способ - перевести на TypeScript собственное React-приложение со строгим режимом. Ошибки компилятора будут указывать ровно на те места, где понимание типов расходится с кодом. Параллельно полезно читать типы популярных библиотек: как они описывают пропсы, хуки и generics.

TypeScript - часть программы трека Frontend на React: на менторстве типизация проверяется на ревью каждого проекта и отрабатывается на мок-собеседованиях. Как устроены занятия, описано на странице как проходит менторство.

Вопросы по теме

Можно ли откликаться на вакансии junior frontend без знания TypeScript?
Формально можно, но в большинстве современных React-проектов код пишется на TypeScript, и его знание часто указано в требованиях. Базовый уровень - типизация пропсов, состояния, ответов API и событий - стоит освоить до откликов: это заметно расширяет число подходящих вакансий.
Чем type отличается от interface в TypeScript?
Оба описывают форму объекта. Interface можно расширять через extends и дополнять повторным объявлением с тем же именем, а type умеет описывать union-типы, кортежи и производные типы. В проекте обычно договариваются об одном стиле; на собеседовании важно показать, что вы понимаете эту разницу.
Почему any считается плохой практикой?
any отключает проверку типов для значения и всего, что из него получено, поэтому ошибки снова обнаруживаются только во время работы программы. Если тип заранее неизвестен, безопаснее unknown: он заставляет сначала проверить значение и только потом с ним работать.
Сколько времени нужно, чтобы освоить TypeScript на уровне junior?
Если JavaScript уже уверенный, базовый TypeScript осваивается за несколько недель практики на своём проекте. Быстрее всего учиться, переводя на TypeScript собственное React-приложение: ошибки компилятора сразу показывают, где в понимании типов есть пробелы.
Нужно ли знать продвинутые возможности TypeScript на собеседовании junior?
Условные и сопоставленные типы на уровне junior спрашивают редко. Гораздо чаще проверяют union-типы и сужение, generics, utility types, разницу между any и unknown и умение типизировать компонент React. Уверенное владение этой базой ценится выше, чем поверхностное знакомство со сложными конструкциями.

Читайте также

Все статьи

Обсудим вашу подготовку?

Напишите, что уже умеете и с чем возникли трудности. Если есть проект, пришлите ссылку на него.

Отвечаю лично, поэтому прошу рассказать о ситуации подробно. Все поля обязательны, кроме отмеченных. После отправки покажу ссылку на мой Telegram: напишите туда, и начнём разговор.

Что не получается, что уже пробовали. От 100 знаков, сейчас 0.
Где работали или учились, сколько лет, какой стек, сколько откликов и собеседований. От 100 знаков, сейчас 0.
PDF или DOCX, до 5 МБ. Файл видит только администратор.
GitHub, hh, LinkedIn, сайт. Можно несколько, через пробел или с новой строки.