← Назад к вопросам

Что является результатом компиляции TypeScript кода?

2.0 Middle🔥 231 комментариев
#JavaScript Core#TypeScript

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

TypeScript Компиляция: От источника к JavaScript

TypeScript компиляция — это процесс преобразования TypeScript кода в JavaScript, который может выполняться в браузере и Node.js. Это не просто удаление аннотаций типов. За 10+ лет я видел множество скрытых дилемм в процессе компиляции, которые могут привести к ошибкам.

Основной процесс компиляции

Входные данные

// main.ts (исходный TypeScript код)
interface User {
  id: number;
  name: string;
  email: string;
}

function getUser(id: number): User {
  return {
    id: id,
    name: "John",
    email: "john@example.com"
  };
}

const user: User = getUser(1);
console.log(user.name);

Результат компиляции (main.js)

// main.js (выходной JavaScript код)
function getUser(id) {
  return {
    id: id,
    name: "John",
    email: "john@example.com"
  };
}

const user = getUser(1);
console.log(user.name);

Ключевое замечание: Все типы и интерфейсы полностью удаляются. В runtime не остаётся информации о типах.

Что именно удаляется

1. Type аннотации

// TypeScript
let name: string = "John";
const age: number = 30;
const active: boolean = true;

// Компилируется в
let name = "John";
const age = 30;
const active = true;

2. Интерфейсы и Type Aliases

// TypeScript
interface Person {
  name: string;
  age: number;
}

type Status = 'active' | 'inactive';

const person: Person = { name: "John", age: 30 };
const status: Status = 'active';

// Компилируется в
const person = { name: "John", age: 30 };
const status = 'active';

3. Generic типы

// TypeScript
function getId<T extends { id: number }>(obj: T): number {
  return obj.id;
}

const result = getId({ id: 1, name: "John" });

// Компилируется в
function getId(obj) {
  return obj.id;
}

const result = getId({ id: 1, name: "John" });

4. Модификаторы доступа (access modifiers)

// TypeScript
class User {
  private id: number;
  public name: string;
  protected email: string;
  readonly role: string = 'user';

  constructor(id: number, name: string) {
    this.id = id;
    this.name = name;
  }
}

// Компилируется в
class User {
  constructor(id, name) {
    this.id = id;
    this.name = name;
    this.role = 'user';
  }
}

Компиляция с target параметром

Выходной JavaScript зависит от параметра target в tsconfig.json:

ES2015 (ES6) - modern browsers

// TypeScript
const numbers: number[] = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

// target: "ES2015" => JavaScript
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

ES5 - старые браузеры

// TypeScript
const numbers: number[] = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

// target: "ES5" => JavaScript
var numbers = [1, 2, 3];
var doubled = numbers.map(function(n) { return n * 2; });
// Стрелочные функции заменены на function

ES2020+

// TypeScript
const value = obj?.property ?? 'default';

// target: "ES2020" => JavaScript (optional chaining и nullish coalescing остаются)
const value = obj?.property ?? 'default';

// target: "ES5" => JavaScript (нужны полифиллы)
const value = (obj === null || obj === void 0) ? void 0 : obj.property;
// Вместо ?. используется явная проверка

Пример полной компиляции

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "declaration": true
  }
}

Исходные файлы TypeScript

// src/types.ts
export interface User {
  id: number;
  name: string;
}

// src/api.ts
import { User } from './types';

export async function fetchUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  const data: User = await response.json();
  return data;
}

// src/main.ts
import { fetchUser } from './api';

const user = await fetchUser(1);
console.log(user.name);

Результат компиляции

// dist/types.js (пусто - только типы)

// dist/api.js
export async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`);
  const data = await response.json();
  return data;
}

// dist/main.js
import { fetchUser } from './api.js';

const user = await fetchUser(1);
console.log(user.name);

Declaration файлы (.d.ts)

Если в tsconfig declaration: true, генерируются файлы типов:

// dist/types.d.ts
export interface User {
  id: number;
  name: string;
}

// dist/api.d.ts
import { User } from './types';
export declare function fetchUser(id: number): Promise<User>;

// dist/main.d.ts

Эти .d.ts файлы позволяют другим проектам TypeScript использовать типы из вашей библиотеки.

Source Maps

При компиляции можно генерировать source maps для отладки:

{
  "compilerOptions": {
    "sourceMap": true
  }
}

Результат:

dist/
  main.js
  main.js.map     <-- Маппинг между TypeScript и JavaScript
  main.d.ts

В DevTools можно отладить исходный TypeScript код вместо скомпилированного JavaScript.

Компиляция на лету (transpilation)

В dev среде (Webpack, Vite, Next.js) компиляция часто происходит на лету:

# dev сервер с HMR
npm run dev

# Внутри:
# 1. Браузер запрашивает main.ts
# 2. Bundler перехватывает, компилирует в JS
# 3. Отправляет JavaScript в браузер
# 4. На изменение - перекомпилирует и обновляет (HMR)

Production сборка

npm run build

# Результат:
# 1. Компилирует TypeScript -> JavaScript
# 2. Бандлит все модули
# 3. Минифицирует (terser)
# 4. Оптимизирует (tree shaking)
# 5. Генерирует source maps (опционально)

Пример с Next.js

$ npm run build

> next build

Compiling TypeScript...
Generating static pages...

✓ Compiled successfully
✓ Linted successfully
✓ Collecting page data
✓ Generating optimized images

Routes (pages):
  ✓ /
  ✓ /api/users/[id]

static/chunks/
  main-123abc.js (45KB)
  vendor-456def.js (120KB)

Частые ошибки

Ошибка 1: Забыть про компиляцию для production

# ❌ НЕПРАВИЛЬНО: Отправить исходный TypeScript
zip -r build.zip src/

# ✅ ПРАВИЛЬНО: Скомпилировать
npm run build
zip -r build.zip dist/

Ошибка 2: Неправильный target для environment

{
  "compilerOptions": {
    "target": "ES2020"  // Некоторые старые браузеры не поддерживают
  }
}

// Нужно проверить что браузеры это поддерживают
// или использовать полифиллы

Ошибка 3: Надеяться что runtime типы существуют

// TypeScript
function isUser(obj: unknown): obj is User {
  // return obj instanceof User; // ❌ User не существует в runtime!
  
  // ✅ ПРАВИЛЬНО: Проверить структуру
  return typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj;
}

Итоговый вывод

TypeScript компилируется в обычный JavaScript путём:

  1. Удаления всех типов и интерфейсов — они нужны только для разработчика
  2. Преобразования современного синтаксиса — в зависимости от target
  3. Сохранения логики — весь код остаётся тем же
  4. Генерации source maps — для отладки

Это означает, что TypeScript не добавляет overhead в production. Вы получаете типобезопасность в разработке, а в production — чистый JavaScript, который работает так же быстро.