Node.js выполняет только JavaScript. Для запуска TypeScript-кода нужно либо скомпилировать его заранее (tsc), либо использовать runtime-транспайлер.
ts-node — интерпретатор, который компилирует TypeScript на лету:
npm install -D ts-node typescript @types/node
# Запуск скрипта:
npx ts-node src/index.ts
# REPL:
npx ts-nodeКонфигурация в tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src"
},
"ts-node": {
"transpileOnly": true
}
}tsx (TypeScript Execute) — значительно быстрее ts-node, использует esbuild:
npm install -D tsx
# Запуск:
npx tsx src/index.ts
# Watch режим:
npx tsx watch src/index.tstsx не выполняет проверку типов — только транспиляция. Для проверки используйте tsc --noEmit отдельно.
Без этого пакета TypeScript не знает о Node.js API:
npm install -D @types/nodeimport fs from 'fs'
import path from 'path'
import { createServer } from 'http'
// Теперь все Node.js типы доступны:
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Hello TypeScript!')
})CommonJS (классический Node.js):
{ "module": "CommonJS" }// Компилируется в require/module.exports
import express from 'express' // -> const express = require('express')ESM (современный):
{ "module": "Node16" }// Остаётся как import/export
// Файлы должны быть .mts или package.json: "type": "module"
import express from 'express'{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "Node16",
"moduleResolution": "Node16",
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit"
}
}Node.js 22.6+ поддерживает TypeScript без транспайлера (экспериментально):
node --experimental-strip-types script.ts| Инструмент | Скорость | Typecheck | Подходит для |
|------------|----------|-----------|--------------|
| ts-node | Медленно | Да | Разработка |
| tsx | Быстро | Нет | Разработка, scripts |
| tsc + node | — | Да | Production |
| esbuild | Очень быстро | Нет | Сборка |
Симуляция Node.js TypeScript окружения: типизированный HTTP-сервер, модули, работа с файлами — паттерны из реального TS/Node кода
// В реальном проекте это TypeScript + Node.js.
// Здесь симулируем те же паттерны в чистом JS.
// --- Симуляция типизированных Node.js модулей ---
// В TS: import { readFileSync } from 'fs'
// Тип: (path: string, encoding: 'utf-8') => string
const fs = {
readFileSync: (filePath, encoding) => {
// Симуляция чтения файла
const files = {
'/app/config.json': JSON.stringify({ port: 3000, debug: true }),
'/app/data.txt': 'Hello, TypeScript!',
}
if (!files[filePath]) throw new Error(`ENOENT: no such file ${filePath}`)
return files[filePath]
},
existsSync: (filePath) => {
return ['/app/config.json', '/app/data.txt'].includes(filePath)
}
}
// В TS: import path from 'path'
const path = {
join: (...parts) => parts.join('/').replace(/\/+/g, '/'),
resolve: (base, ...parts) => path.join(base, ...parts),
extname: (filePath) => {
const dot = filePath.lastIndexOf('.')
return dot >= 0 ? filePath.slice(dot) : ''
},
basename: (filePath) => filePath.split('/').pop(),
}
// --- HTTP сервер (как express/http в TypeScript) ---
// В TS:
// interface Request { method: string; url: string; body?: unknown }
// interface Response { status: (code: number) => Response; json: (data: unknown) => void }
class MockServer {
constructor() {
this.routes = new Map()
this.middleware = []
}
use(middleware) {
this.middleware.push(middleware)
}
get(route, handler) {
this.routes.set('GET:' + route, handler)
}
post(route, handler) {
this.routes.set('POST:' + route, handler)
}
// Симуляция обработки запроса
handle(method, url, body = null) {
const req = { method, url, body, params: {}, query: {} }
const res = {
statusCode: 200,
data: null,
status(code) { this.statusCode = code; return this },
json(data) { this.data = data; return this },
send(text) { this.data = text; return this },
}
// Применяем middleware
let idx = 0
const next = () => {
if (idx < this.middleware.length) {
this.middleware[idx++](req, res, next)
} else {
// Ищем обработчик
const handler = this.routes.get(method + ':' + url)
if (handler) handler(req, res)
else res.status(404).json({ error: 'Not Found' })
}
}
next()
return { status: res.statusCode, body: res.data }
}
}
// --- Типизированные хендлеры (как в TS + Express) ---
// TS: interface User { id: number; name: string; email: string }
// TS: const users: User[] = [...]
const users = [
{ id: 1, name: 'Алексей', email: 'alex@example.com' },
{ id: 2, name: 'Мария', email: 'maria@example.com' },
]
const app = new MockServer()
// Logger middleware
// TS: (req: Request, res: Response, next: NextFunction) => void
app.use((req, res, next) => {
console.log(`[LOG] ${req.method} ${req.url}`)
next()
})
// В TS: app.get('/users', (req: Request, res: Response) => { ... })
app.get('/users', (req, res) => {
res.json({ users, total: users.length })
})
app.get('/config', (req, res) => {
const configPath = '/app/config.json'
if (fs.existsSync(configPath)) {
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
res.json(data)
} else {
res.status(404).json({ error: 'Config not found' })
}
})
app.post('/users', (req, res) => {
const newUser = { id: users.length + 1, ...req.body }
users.push(newUser)
res.status(201).json(newUser)
})
// --- Демонстрация ---
console.log('=== HTTP сервер ===')
let result = app.handle('GET', '/users')
console.log('GET /users:', JSON.stringify(result.body))
result = app.handle('POST', '/users', { name: 'Иван', email: 'ivan@example.com' })
console.log('POST /users:', JSON.stringify(result.body))
result = app.handle('GET', '/unknown')
console.log('GET /unknown status:', result.status)
console.log('\n=== Работа с файлами ===')
console.log('config exists:', fs.existsSync('/app/config.json'))
result = app.handle('GET', '/config')
console.log('GET /config:', result.body)
console.log('\n=== path utils ===')
console.log('join:', path.join('/src', 'utils', 'date.ts'))
console.log('extname:', path.extname('index.ts'))
console.log('basename:', path.basename('/src/utils/date.ts'))Node.js выполняет только JavaScript. Для запуска TypeScript-кода нужно либо скомпилировать его заранее (tsc), либо использовать runtime-транспайлер.
ts-node — интерпретатор, который компилирует TypeScript на лету:
npm install -D ts-node typescript @types/node
# Запуск скрипта:
npx ts-node src/index.ts
# REPL:
npx ts-nodeКонфигурация в tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"outDir": "./dist",
"rootDir": "./src"
},
"ts-node": {
"transpileOnly": true
}
}tsx (TypeScript Execute) — значительно быстрее ts-node, использует esbuild:
npm install -D tsx
# Запуск:
npx tsx src/index.ts
# Watch режим:
npx tsx watch src/index.tstsx не выполняет проверку типов — только транспиляция. Для проверки используйте tsc --noEmit отдельно.
Без этого пакета TypeScript не знает о Node.js API:
npm install -D @types/nodeimport fs from 'fs'
import path from 'path'
import { createServer } from 'http'
// Теперь все Node.js типы доступны:
const server = createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end('Hello TypeScript!')
})CommonJS (классический Node.js):
{ "module": "CommonJS" }// Компилируется в require/module.exports
import express from 'express' // -> const express = require('express')ESM (современный):
{ "module": "Node16" }// Остаётся как import/export
// Файлы должны быть .mts или package.json: "type": "module"
import express from 'express'{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "Node16",
"moduleResolution": "Node16",
"rootDir": "./src",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"typecheck": "tsc --noEmit"
}
}Node.js 22.6+ поддерживает TypeScript без транспайлера (экспериментально):
node --experimental-strip-types script.ts| Инструмент | Скорость | Typecheck | Подходит для |
|------------|----------|-----------|--------------|
| ts-node | Медленно | Да | Разработка |
| tsx | Быстро | Нет | Разработка, scripts |
| tsc + node | — | Да | Production |
| esbuild | Очень быстро | Нет | Сборка |
Симуляция Node.js TypeScript окружения: типизированный HTTP-сервер, модули, работа с файлами — паттерны из реального TS/Node кода
// В реальном проекте это TypeScript + Node.js.
// Здесь симулируем те же паттерны в чистом JS.
// --- Симуляция типизированных Node.js модулей ---
// В TS: import { readFileSync } from 'fs'
// Тип: (path: string, encoding: 'utf-8') => string
const fs = {
readFileSync: (filePath, encoding) => {
// Симуляция чтения файла
const files = {
'/app/config.json': JSON.stringify({ port: 3000, debug: true }),
'/app/data.txt': 'Hello, TypeScript!',
}
if (!files[filePath]) throw new Error(`ENOENT: no such file ${filePath}`)
return files[filePath]
},
existsSync: (filePath) => {
return ['/app/config.json', '/app/data.txt'].includes(filePath)
}
}
// В TS: import path from 'path'
const path = {
join: (...parts) => parts.join('/').replace(/\/+/g, '/'),
resolve: (base, ...parts) => path.join(base, ...parts),
extname: (filePath) => {
const dot = filePath.lastIndexOf('.')
return dot >= 0 ? filePath.slice(dot) : ''
},
basename: (filePath) => filePath.split('/').pop(),
}
// --- HTTP сервер (как express/http в TypeScript) ---
// В TS:
// interface Request { method: string; url: string; body?: unknown }
// interface Response { status: (code: number) => Response; json: (data: unknown) => void }
class MockServer {
constructor() {
this.routes = new Map()
this.middleware = []
}
use(middleware) {
this.middleware.push(middleware)
}
get(route, handler) {
this.routes.set('GET:' + route, handler)
}
post(route, handler) {
this.routes.set('POST:' + route, handler)
}
// Симуляция обработки запроса
handle(method, url, body = null) {
const req = { method, url, body, params: {}, query: {} }
const res = {
statusCode: 200,
data: null,
status(code) { this.statusCode = code; return this },
json(data) { this.data = data; return this },
send(text) { this.data = text; return this },
}
// Применяем middleware
let idx = 0
const next = () => {
if (idx < this.middleware.length) {
this.middleware[idx++](req, res, next)
} else {
// Ищем обработчик
const handler = this.routes.get(method + ':' + url)
if (handler) handler(req, res)
else res.status(404).json({ error: 'Not Found' })
}
}
next()
return { status: res.statusCode, body: res.data }
}
}
// --- Типизированные хендлеры (как в TS + Express) ---
// TS: interface User { id: number; name: string; email: string }
// TS: const users: User[] = [...]
const users = [
{ id: 1, name: 'Алексей', email: 'alex@example.com' },
{ id: 2, name: 'Мария', email: 'maria@example.com' },
]
const app = new MockServer()
// Logger middleware
// TS: (req: Request, res: Response, next: NextFunction) => void
app.use((req, res, next) => {
console.log(`[LOG] ${req.method} ${req.url}`)
next()
})
// В TS: app.get('/users', (req: Request, res: Response) => { ... })
app.get('/users', (req, res) => {
res.json({ users, total: users.length })
})
app.get('/config', (req, res) => {
const configPath = '/app/config.json'
if (fs.existsSync(configPath)) {
const data = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
res.json(data)
} else {
res.status(404).json({ error: 'Config not found' })
}
})
app.post('/users', (req, res) => {
const newUser = { id: users.length + 1, ...req.body }
users.push(newUser)
res.status(201).json(newUser)
})
// --- Демонстрация ---
console.log('=== HTTP сервер ===')
let result = app.handle('GET', '/users')
console.log('GET /users:', JSON.stringify(result.body))
result = app.handle('POST', '/users', { name: 'Иван', email: 'ivan@example.com' })
console.log('POST /users:', JSON.stringify(result.body))
result = app.handle('GET', '/unknown')
console.log('GET /unknown status:', result.status)
console.log('\n=== Работа с файлами ===')
console.log('config exists:', fs.existsSync('/app/config.json'))
result = app.handle('GET', '/config')
console.log('GET /config:', result.body)
console.log('\n=== path utils ===')
console.log('join:', path.join('/src', 'utils', 'date.ts'))
console.log('extname:', path.extname('index.ts'))
console.log('basename:', path.basename('/src/utils/date.ts'))Реализуй `createScript(name, fn)` — фабрику для CLI-скриптов в стиле Node.js. Возвращаемый объект имеет метод `run(args)`, который: вызывает `fn(args)`, перехватывает ошибки (выводит `[ERROR] scriptName: сообщение`), и возвращает `{ success: true, result }` или `{ success: false, error }`. Также добавь метод `withTimeout(ms)` — если `fn` работает дольше ms миллисекунд, завершается с ошибкой "Timeout".
В run(): try { const result = fn(args); return { success: true, result } } catch(e) { console.log("[ERROR] " + name + ": " + e.message); return { success: false, error: e.message } }. В withTimeout: setTimeout с resolve({ success: false, error: "Timeout" }) после ms миллисекунд.
Токены для AI-помощника закончились
Купи токены чтобы задавать вопросы AI прямо в уроке