Что является результатом компиляции TypeScript кода?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
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 путём:
- Удаления всех типов и интерфейсов — они нужны только для разработчика
- Преобразования современного синтаксиса — в зависимости от target
- Сохранения логики — весь код остаётся тем же
- Генерации source maps — для отладки
Это означает, что TypeScript не добавляет overhead в production. Вы получаете типобезопасность в разработке, а в production — чистый JavaScript, который работает так же быстро.