Backend Typescript 1.0.0 Help

TypeScript

TypeScript — это надстройка над JavaScript, добавляющая статическую систему типов, инструменты для проверки кода на этапе разработки и улучшенную поддержку крупных проектов. Он компилируется в обычный JS, поэтому запускается везде, где работает JS: в Node.js и в браузере. Ниже — что именно добавляет TS и как стажёру, знакомому только с серверным JS, грамотно на него перейти.

Что добавляет TypeScript поверх JavaScript

  • Статическая типизация: объявление типов для переменных, параметров, возвращаемых значений функций и структур данных.

  • Инференс типов: TS умеет выводить типы автоматически, не требуя аннотаций везде.

  • Проверка на этапе компиляции: ловит опечатки, несоответствия контрактам и потенциальные ошибки ещё до запуска.

  • Современный синтаксис: поддержка последних возможностей JS (ESNext), включая import/export, async/await, декораторы (экспериментально) и т. п.

  • Инструменты для больших кодовых баз: интерфейсы, дженерики, объединения типов, пересечения типов, утилитные типы.

  • Более умный редакторский опыт: автодополнение, навигация по коду, рефакторинги и подсказки становятся точнее благодаря типам.

Базовые типы и аннотации

Самые часто используемые типы: string, number, boolean, null, undefined, symbol, bigint, unknown, any, never, а также object, массивы T[] и кортежи [T1, T2].

// Явные аннотации типов let message: string = "Hello"; let count: number = 42; let ok: boolean = true; // Массивы и кортежи const nums: number\[] = \[1, 2, 3]; const pair: \[string, number] = \["id", 10]; // Объекты и интерфейсы interface User { id: string; email?: string; // вопросительный знак — поле необязательно } const u: User = {id: "u1"};

Структурная типизация и контракты

TS использует структурную типизацию: совместимость определяется формой объекта (набором полей), а не именем типа.

interface HasId { id: string; } type WithIdAndName = { id: string; name: string; }; const w: WithIdAndName = {id: "1", name: "Alice"}; const h: HasId = w; // ОК: у w есть поле id\:string

Интерфейсы и type-алиасы

И interface, и type объявляют формы типов. interface поддерживает декларативное расширение (merging), type — более универсален (можно описывать объединения, пересечения и пр.).

interface A { x: number; } interface A { y: number; } // merging: теперь A имеет x и y type B = { x: number } & { y: number }; // пересечение даёт { x; y }

Объединения, пересечения, литеральные и перечислимые типы

type Id = string | number; // объединение type Point2D = { x: number } & { y: number }; // пересечение // Литеральные типы и сужение type Direction = "up" | "down" | "left" | "right"; enum Role { Admin = "admin", User = "user", }

Сужение типов (type narrowing) и проверки

TS анализирует ветвления и проверки, чтобы «сузить» тип к более конкретному.

function printId(id: string | number) { if (typeof id === "string") { console.log(id.toUpperCase()); } else { console.log(id.toFixed(2)); } } function isUser(x: unknown): x is { id: string } { return typeof x === "object" && x !== null && "id" in x; }

Дженерики (обобщения)

Дженерики позволяют писать переиспользуемый код, сохраняющий информацию о типах.

function wrap<T>(value: T) { return {value}; } const x = wrap<number>(42); // x: { value: number } const y = wrap("str"); // инференс T = string

Полезные утилитные типы

  • Partial<T>, Required<T>, Readonly<T>

  • Pick<T, K>, Omit<T, K>

  • Record<K, T>, NonNullable<T>, ReturnType<F>

type User = { id: string; email?: string }; type UserPatch = Partial<User>; // все поля необязательны type UserRequired = Required<User>; // все обязательны type OnlyId = Pick<User, "id">;

Функции, this и перегрузки

Аннотируйте параметры и возвращаемые значения. Для разных сигнатур используйте перегрузки.

function len(x: string): number; function len(x: any[]): number; function len(x: string | any[]) { return x.length; }

Классы, модификаторы и поля

TS добавляет модификаторы public, private, protected, readonly, а также поля инициализации прямо в сигнатуре конструктора.

class Repo { constructor(private readonly url: string) { } connect(): void { /* ... */ } } const r = new Repo("postgres://...");

Строгий режим и работа с null/undefined

Включите строгий режим, чтобы компилятор помогал больше: "strict": true, включая strictNullChecks.

function findEmail(u?: { email?: string }) { // Опциональная последовательность и оператор объединения с null return u?.email ?? "no-email@example.com"; }

Переезд с серверного JS на TypeScript — практическая стратегия

Шаг 1. Подготовка окружения

  • Добавьте TS в проект: npm i -D typescript.

  • Инициализируйте конфиг: npx tsc --init.

  • Рекомендуемые опции для Node.js-проекта:

    { "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "outDir": "dist", "rootDir": "src", "resolveJsonModule": true, "forceConsistentCasingInFileNames": true }, "include": [ "src" ] }

Шаг 2. Мягкая типизация существующего кода

  • Включите поддержку JS-файлов в сборке: "allowJs": true и, по желанию, "checkJs": true для постепенной проверки JSDoc-типов.

  • Начните добавлять JSDoc-типы в JS-файлы, не переименовывая их в .ts. Это даст подсказки без резкого порога.

  • Постепенно переименовывайте файлы из .js в .ts, начиная с листовых модулей (не переиспользуемых другими).

Шаг 3. Типизация внешних зависимостей

  • Если пакет не имеет встроенных типов, установите их: npm i -D @types/<pkg>.

  • Пишите собственные декларации для внутренних библиотек: *.d.ts в папке types и добавьте её в typeRoots, если нужно.

Шаг 4. Ужесточение конфигурации

  • Включайте строгие флаги постепенно: noImplicitAny, noImplicitThis, strictNullChecks, noUncheckedIndexedAccess.

  • Наводите порядок: устраняйте any, вводите интерфейсы/типы, покрывайте участки кода тестами.

Шаг 5. Сборка и запуск

  • В разработке удобно использовать tsx или ts-node:

    npm i -D tsx # или npm i -D ts-node
  • В продакшн собирайте в JS:

    npx tsc node dist/index.js

Лучшие практики для серверного TypeScript

  • С самого начала включите "strict": true и "skipLibCheck": true (ускоряет сборку, не проверяя внешние типы).

  • Фиксируйте интерфейсы доменных сущностей в types/ или domain/. Поддерживайте их как «контракты» между модулями.

  • Предпочитайте unknown вместо any на границах ввода (например, при парсинге JSON), затем выполняйте проверку и сужение.

  • Используйте утилитные типы для DTO: Pick, Omit, Partial, чтобы не дублировать поля.

  • Поддерживайте единый стиль импорта/экспорта (ESM или CJS) и настройте линтер (ESLint) + форматтер (Prettier).

Мини-проект: пример и как запустить

Создадим минимальный сервер на Node.js с TypeScript.

# 1) Инициализируем проект npm init -y # 2) Ставим зависимости для TS-разработки npm i -D typescript tsx @types/node # 3) Инициализируем tsconfig npx tsc --init

Отредактируем tsconfig.json (минимально необходимое):

{ "compilerOptions": { "target": "ES2020", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "rootDir": "src", "outDir": "dist" }, "include": [ "src" ] }

Создадим файл src/index.ts:

// Мини-сервер HTTP без фреймворков import http from "node:http"; const port: number = Number(process.env.PORT ?? 3000); const server = http.createServer((req, res) => { if (req.url === "/health") { res.statusCode = 200; res.setHeader("Content-Type", "application/json; charset=utf-8"); res.end(JSON.stringify({ok: true, ts: new Date().toISOString()})); return; } res.statusCode = 200; res.setHeader("Content-Type", "text/plain; charset=utf-8"); res.end("Hello from TypeScript!"); }); server.listen(port, () => { console.log(`Server is listening on http://localhost:${port}`); });

Добавим скрипты в package.json:

{ "type": "module", "scripts": { "dev": "tsx watch src/index.ts", "build": "tsc", "start": "node dist/index.js" } }

Запуск:

  • Режим разработки: горячий перезапуск

    npm run dev
  • Сборка и продакшн-запуск:

    npm run build npm start
Last modified: 01 October 2025