Урок 49 из 49 · Месяц 6. TypeScript и выход на работу

Завершение проекта и подготовка к собеседованию

Содержание урока

Это финальный урок курса: за полгода вы прошли путь от первого тега до React-приложения на TypeScript. Осталось довести проекты до состояния «не стыдно показать», собрать резюме и портфолио, повторить вопросы, которые чаще всего задают junior-фронтендерам, и подготовиться к финальному экзамену. Здесь собраны чек-листы, короткие ответы на частые вопросы и примеры задач для лайвкодинга.

Завершение проекта

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

Чек-лист готового проекта

  • Проект задеплоен и открывается по ссылке (Vercel, Netlify, GitHub Pages или другой хостинг).
  • Работает на телефоне: проверено на ширине 375px (урок Tailwind CSS и адаптивная вёрстка).
  • Есть состояния загрузки, ошибки и пустого списка.
  • Нет ошибок в консоли браузера и в npm run build.
  • Нет секретов в репозитории: .env в .gitignore, в README — пример .env.example.
  • Понятная структура папок (урок Архитектура проектов).
  • Осмысленные коммиты, а не десять коммитов «fix».
  • Есть README.

README, который читают

README — это обложка проекта. Работодатель открывает его первым.

# Shop — интернет-магазин электроники

Демо: https://your-shop.example.com

Каталог с фильтрами и поиском, корзина, авторизация по JWT.

## Стек
React 19, TypeScript, Vite, TanStack Query, Zustand, React Router, Tailwind CSS

## Возможности
- фильтрация и сортировка через query-параметры
- корзина сохраняется после перезагрузки
- регистрация и вход, защищённые маршруты
- адаптивная вёрстка от 375px

## Запуск
npm install
cp .env.example .env
npm run dev

Добавьте 1–2 скриншота или короткую GIF-анимацию работы приложения — так проект понятен за 10 секунд.

Резюме и портфолио

Резюме junior-фронтендера

Одна страница, без лишнего. Структура:

  1. Имя, позиция — «Frontend-разработчик (React, TypeScript)».
  2. Контакты — Telegram, почта, GitHub, ссылка на портфолио.
  3. Навыки — только то, что можете объяснить на собеседовании: HTML, CSS, Tailwind, JavaScript, TypeScript, React, React Router, TanStack Query, Zustand, react-hook-form, Git, REST API.
  4. Проекты — 2–4 лучших: название, одна строка о проекте, стек, что сделали лично вы, ссылки на демо и код.
  5. Опыт — если есть (даже не IT: ответственность и работа в команде тоже ценятся).
  6. Образование и курсы.

Пример описания проекта:

Shop — интернет-магазин электроники
React, TypeScript, TanStack Query, Zustand, Tailwind
• Каталог с фильтрацией, сортировкой и пагинацией через query-параметры
• Авторизация по JWT, защищённые маршруты, обновление токена
• Типы API сгенерированы из Swagger (Orval)
Демо: ... · Код: ...

GitHub как портфолио

  • Закрепите (Pin) лучшие репозитории на главной странице профиля.
  • У каждого — описание, ссылка на демо и README.
  • Удалите или сделайте приватными учебные «пробы» без README.
  • Зелёные квадратики активности — плюс, но качество кода важнее.

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

Ниже — короткие ответы. На собеседовании говорите своими словами и добавляйте пример из своего проекта.

HTML и CSS

Что такое семантическая вёрстка? Использование тегов по смыслу: header, nav, main, article, footer, button. Помогает SEO, доступности и читаемости кода.

Блочная модель? Элемент = контент + padding + border + margin. При box-sizing: border-box ширина включает padding и border.

Чем отличаются position: relative, absolute, fixed, sticky? relative — смещение от своего места; absolute — относительно ближайшего позиционированного предка; fixed — относительно окна; sticky — «прилипает» при прокрутке.

Flexbox или Grid? Flex — раскладка в одном направлении (строка или колонка), Grid — двумерная сетка (строки и колонки сразу).

Как сделать адаптивную вёрстку? Медиазапросы, относительные единицы (rem, %, vw), flex/grid, подход mobile-first.

Специфичность селекторов? Приоритет: !important > инлайн-стиль > #id > .class, [attr], :hover > тег. При равной специфичности побеждает правило ниже.

JavaScript

let, const, var? var — функциональная область видимости и всплытие; let и const — блочная область, const нельзя переприсвоить (но объект внутри менять можно).

== и ===? == приводит типы ("5" == 5 → true), === сравнивает без приведения. Используем ===.

Что такое замыкание? Функция, которая помнит переменные из места, где была создана, даже после того, как внешняя функция завершилась.

Как работает Event Loop? JS однопоточный. Синхронный код выполняется в стеке вызовов, асинхронные колбэки ждут в очередях: сначала выполняются микрозадачи (промисы), потом макрозадачи (setTimeout, события).

Что выведет код?

console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);
// 1, 4, 3, 2

Promise и async/await? Promise — объект будущего результата (pending → fulfilled/rejected). async/await — более удобная запись работы с промисами; ошибки ловим через try/catch.

map, filter, reduce, forEach? map — новый массив преобразованных элементов, filter — отфильтрованный, reduce — сводит к одному значению, forEach — просто перебор, ничего не возвращает.

Копирование объектов? Spread { ...obj } делает поверхностную копию; для глубокой — structuredClone(obj).

React

Что такое Virtual DOM? Лёгкое представление интерфейса в памяти. React сравнивает новое и старое дерево и меняет в настоящем DOM только то, что изменилось.

Пропсы и состояние? Пропсы передаёт родитель, компонент их не меняет. Состояние (useState) — внутренние данные компонента; при изменении компонент перерисовывается.

Зачем key в списках? Чтобы React понимал, какой элемент добавлен, удалён или перемещён. Ключ — стабильный уникальный id, не индекс массива, если список меняется.

Как работает useEffect? Запускает побочный эффект после отрисовки. Массив зависимостей: [] — один раз после монтирования, [a] — при изменении a, без массива — после каждого рендера. Функция-возврат — очистка.

useMemo и useCallback? useMemo запоминает результат вычисления, useCallback — саму функцию. Нужны против лишних пересчётов и ререндеров, но не везде.

Как передать данные между далёкими компонентами? Поднять состояние, Context, менеджер состояния (Zustand), а данные с сервера — через TanStack Query.

Зачем TanStack Query, если есть useEffect + fetch? Кэш, повторные запросы, состояния загрузки и ошибки, инвалидация после мутаций — без ручного кода.

TypeScript

Зачем TypeScript? Ошибки видны до запуска, автодополнение, безопасный рефакторинг, код документирует сам себя.

type или interface? Оба описывают объекты. interface расширяется через extends и может объявляться повторно, type умеет union, кортежи и примитивы.

any и unknown? any отключает проверку, unknown требует проверить тип перед использованием.

Что такое generic? Тип-параметр: одна функция или тип работает с разными данными без потери типизации — function first<T>(arr: T[]): T | undefined.

Utility types? Partial, Pick, Omit, Record — создают новые типы на основе существующих.

Общие вопросы

Что происходит, когда вводишь адрес в браузере? DNS находит IP сервера, устанавливается соединение (HTTPS), браузер отправляет запрос, получает HTML, разбирает его, загружает CSS и JS, строит DOM и отрисовывает страницу.

HTTP-методы и коды? GET — получить, POST — создать, PUT/PATCH — обновить, DELETE — удалить. 2xx — успех, 4xx — ошибка клиента (400, 401, 403, 404), 5xx — ошибка сервера.

Где хранить токен? Варианты: память приложения, localStorage (просто, но уязвим к XSS), httpOnly-cookie (недоступна из JS). Хороший ответ — назвать плюсы и минусы.

Лайвкодинг

Лайвкодинг — задача, которую решаете при интервьюере, обычно 20–40 минут. Важен не только ответ, но и то, как вы думаете.

Алгоритм:

  1. Повторите задачу своими словами и уточните условия.
  2. Разберите пример вход → выход.
  3. Проговорите решение, прежде чем писать.
  4. Напишите простое рабочее решение, потом улучшайте.
  5. Проверьте на граничных случаях: пустой массив, одна буква, null.

Задача 1. Уникальные значения

function unique(arr) {
  return [...new Set(arr)];
}

console.log(unique([1, 2, 2, 3, 1])); // [1, 2, 3]

Set хранит только уникальные значения, spread превращает его обратно в массив.

Задача 2. Палиндром

function isPalindrome(str) {
  const clean = str.toLowerCase().replace(/[^a-zа-яё0-9]/g, "");
  return clean === [...clean].reverse().join("");
}

console.log(isPalindrome("А роза упала на лапу Азора")); // true

Задача 3. Подсчёт символов

function countChars(str) {
  const result = {};
  for (const char of str) {
    result[char] = (result[char] ?? 0) + 1;
  }
  return result;
}

console.log(countChars("hello")); // { h: 1, e: 1, l: 2, o: 1 }

Задача 4. React: поиск по списку

import { useState } from "react";

const fruits = ["Яблоко", "Банан", "Апельсин", "Груша"];

export function FruitSearch() {
  const [query, setQuery] = useState("");

  const filtered = fruits.filter((f) => f.toLowerCase().includes(query.toLowerCase()));

  return (
    <div>
      <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Поиск" />
      {filtered.length === 0 ? (
        <p>Ничего не найдено</p>
      ) : (
        <ul>
          {filtered.map((f) => (
            <li key={f}>{f}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

Обратите внимание: отфильтрованный список вычисляется из query, а не хранится в отдельном useState — так нет рассинхронизации.

Финальный экзамен

Формат, сроки и критерии оценки финального экзамена уточните у менторов. Обычно итоговая проверка включает теоретические вопросы, практическое задание и защиту своего проекта.

Что нужно уметь

  • Сверстать адаптивную страницу по макету (семантика, flex/grid, mobile-first, Tailwind или CSS Modules).
  • Писать на JavaScript: массивы и методы перебора, деструктуризация, промисы, async/await, обработка ошибок.
  • Создать React-проект на Vite с TypeScript, типизировать пропсы, состояние и события.
  • Настроить маршрутизацию на React Router, параметры и защищённые страницы.
  • Получать и отправлять данные через TanStack Query (useQuery, useMutation), инвалидировать кэш.
  • Хранить глобальное состояние в Zustand.
  • Делать формы на react-hook-form с валидацией.
  • Работать с JWT-авторизацией и читать Swagger.
  • Объяснить архитектуру своего проекта и принятые решения.
  • Работать с Git: ветки, коммиты, pull request.

Пример контрольной работы

  1. Теория (устно). Три вопроса из списка выше: например, Event Loop, useEffect и его зависимости, разница type и interface.
  2. JavaScript. Напишите функцию groupBy(users, "city"), которая группирует массив объектов по полю. Ожидаемый результат: { "Бишкек": [...], "Ош": [...] }.
  3. React + TypeScript. Сделайте страницу списка задач: загрузка через useQuery, добавление через useMutation, фильтр «все / выполненные / активные». Ожидаемый результат: после добавления список обновляется без перезагрузки страницы.
  4. Вёрстка. Карточка товара по описанию: на телефоне — колонка, от 768px — картинка слева, текст справа.
  5. Защита проекта. 5–7 минут: что за проект, стек, архитектура, самая сложная задача и как вы её решили.

Советы по подготовке

  • Повторяйте по плану: неделя на HTML/CSS/JS, неделя на React и TypeScript.
  • Решайте по 2–3 небольшие задачи в день без ИИ и подсказок (урок ИИ в разработке объясняет, почему).
  • Рассказывайте ответы вслух — другу, в зеркало, на диктофон.
  • Устройте пробное собеседование с одногруппником: один спрашивает, другой отвечает, потом меняетесь.
  • Подготовьте рассказ о проекте заранее и отрепетируйте его по времени.
  • Высыпайтесь перед экзаменом — свежая голова решает быстрее.

Практика

  1. Аудит проекта. Пройдите чек-лист «готового проекта» по своему лучшему проекту и исправьте все пункты. Ожидаемый результат: проект задеплоен, README оформлен, консоль чистая.
  2. Резюме. Составьте резюме на одну страницу по структуре из урока. Ожидаемый результат: файл PDF, который не стыдно отправить, со ссылками на GitHub и демо.
  3. Вопросы вслух. Ответьте вслух на 15 вопросов из урока, записывая себя. Ожидаемый результат: список тем, где вы запнулись, и повторение этих уроков.
  4. Лайвкодинг. Решите задачи из урока с таймером по 15 минут и ещё две новые: flatten (плоский массив из вложенного) и debounce. Ожидаемый результат: рабочие функции и умение объяснить их.
  5. Пробный экзамен. Выполните пример контрольной работы целиком за 3 часа. Ожидаемый результат: работающее приложение в репозитории и подготовленная 5-минутная защита.

Итоги

  • Законченный проект важнее количества: деплой, адаптивность, README, чистая консоль, никаких секретов в Git.
  • Резюме — одна страница, только реальные навыки и 2–4 лучших проекта со ссылками.
  • Повторите ключевые вопросы по HTML, CSS, JS, React и TypeScript и отвечайте своими словами с примерами.
  • На лайвкодинге уточняйте задачу, проговаривайте решение и проверяйте граничные случаи.
  • К финальному экзамену готовьтесь по чек-листу «что нужно уметь»; формат уточните у менторов.
  • Поздравляем с завершением курса — дальше учитесь на реальных задачах и не бойтесь откликаться на вакансии.
Отзыв