Node.js 25 TypeScript, встроенный SQLite и Permission Model
Руководство · Июнь 2026

Node.js 25 TypeScript, SQLite и модель разрешений:
Полное руководство для production

Нативная поддержка TypeScript, встроенный SQLite и гранулярная модель разрешений — всё в Node.js 25+. Это руководство охватывает всё, что нужно знать об этих трёх революционных возможностях: от запуска .ts файлов напрямую без tsc до нуль-конфигурационного хранения данных с node:sqlite и защиты приложений с --permission.

Олег Максимов 13 июня 2026 14 мин чтения

1. Обзор и версионная хронология

Node.js 25+ привносит три революционных нативных возможности в JavaScript-рантайм: нативную поддержку TypeScript через встроенный type stripping, встроенный SQLite через модуль node:sqlite и модель разрешений (Permission Model) для гранулярной безопасности во время выполнения. В этом руководстве подробно рассматриваются все три функции.

Версия Дата релиза TypeScript SQLite Permission Model
v20Апр 2024Экспериментальный (--experimental-permission)
v22Апр 2024Экспериментальный type strippingДобавлен node:sqlite (v22.5.0)Экспериментальный
v23Окт 2024Доработки, .tsx не поддерживаетсяЭкспериментальный
v24Май 2025Функционально завершёнФункционально завершёнФлаг --permission (без experimental-)
v25Окт 2025Стабильный (Stability: 2), V8 14.1СтабильныйДобавлен --allow-net
v26Май 2026Стабильный, в документации как "Modules: TypeScript"СтабильныйСтабильный, поддержка конфиг-файлов

Главный вывод: Начиная с Node.js 25+ (Current) и Node.js 24+ (LTS), все три функции стабильны и готовы к production-использованию.

2. Нативная поддержка TypeScript (Type Stripping)

2.1 Включение TypeScript в Node.js

Есть два способа запускать TypeScript-код в Node.js:

ПодходОписаниеДля кого
Встроенный type stripping (рекомендуется)Node.js удаляет TypeScript-синтаксис во время выполнения, оставляя только JavaScriptПростые TypeScript-проекты, скрипты, прототипы
Полная поддержка через сторонние инструменты (tsx)Полная поддержка TypeScript, включая enums, декораторы, возможности tsconfig.jsonСложные TypeScript-проекты с продвинутыми возможностями

Встроенный type stripping работает по умолчанию — просто запустите:

# Запустить TypeScript-файл напрямую (Node.js 22+)
node app.ts

# Флаги не нужны — type stripping включён по умолчанию в v22+

Чтобы отключить type stripping:

node --no-strip-types app.ts

2.2 Как работает type stripping

Node.js выполняет TypeScript-файлы, заменяя TypeScript-специфичный синтаксис на пробелы (сохраняя номера строк и столбцов в stack trace). Проверка типов не выполняется — это по-прежнему задача tsc в редакторе или CI.

Ключевые принципы:

// Этот код выполняется нативно в Node.js:
function greet(name: string): string {
  return `Hello, ${name}!`;
}

// Аннотации типа `: string` заменяются на пробелы
// Node.js видит: function greet(name) { return `Hello, ${name}!`; }

2.3 Поддерживаемые расширения файлов и модульная система

РасширениеМодульная системаАналог в JS
.tsОпределяется ближайшим package.json.js
.mtsВсегда ES-модуль.mjs
.ctsВсегда CommonJS.cjs
.tsxНе поддерживается

Правила модульной системы для .ts-файлов:

// Правильно:
import './helper.ts';
import { config } from './config.ts';

// Неправильно — будет ошибка:
import './helper';
import { config } from './config';

// Также правильно для CommonJS:
const helper = require('./helper.ts');

2.4 Возможности TypeScript, которые работают и не работают

ВозможностьПоддерживается?Примечания
Аннотации типов (: string)✅ ДаЗаменяются на пробелы
Interfaces✅ ДаУдаляются
Type aliases✅ ДаУдаляются
Generics✅ ДаУдаляются
typeof, keyof, условные типы✅ ДаЧисто типовой уровень
const assertions✅ ДаУдаляются
as-приведения✅ ДаУдаляются
Enums❌ НетERR_UNSUPPORTED_TYPESCRIPT_SYNTAX
Namespaces с runtime-кодом❌ НетНапример, namespace A { export let x = 1 }
Parameter properties❌ Нетconstructor(private x: number)
Декораторы❌ НетВсё ещё Stage 3 TC39 proposal
Пути из tsconfig.json❌ НетИспользуйте subpath imports (#)

2.5 Импорт типов (ключевое слово type)

Из-за того, как работает type stripping, ключевое слово type обязательно в импортах:

// ✅ Правильно — будет работать:
import type { User, Config } from './types.ts';
import { createUser, type UserInput } from './user.ts';

// ❌ Неправильно — будет runtime-ошибка:
import { User, Config } from './types.ts'; // User — тип, а не значение

2.6 Рекомендуемые настройки tsconfig.json

Для проектов, нацеленных на Node.js 25+ со встроенным type stripping:

{
  "compilerOptions": {
    "noEmit": true,
    "target": "esnext",
    "module": "nodenext",
    "rewriteRelativeImportExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true
  }
}

2.7 Полная поддержка TypeScript через сторонние инструменты

# Установка как dev-зависимости
npm install --save-dev tsx

# Запуск напрямую
npx tsx your-file.ts

# Или через node --import
node --import=tsx your-file.ts

2.8 Type Stripping в зависимостях и не-файловых входах

Зависимости внутри node_modules: Node.js отказывается обрабатывать TypeScript-файлы внутри node_modules.

Не-файловые входы:

Путевые алиасы: paths из tsconfig.json не поддерживаются. Используйте subpath imports.

3. Встроенный SQLite (node:sqlite)

3.1 Обзор

import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');
db.exec(`
  CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT UNIQUE
  );
`);

3.2 Класс DatabaseSync

new DatabaseSync(filename[, options])
ПараметрТипПо умолчаниюОписание
filenamestring | Buffer | URLПуть к файлу БД или ':memory:'
options.readonlybooleanfalseТолько чтение
options.createbooleantrueСоздать файл, если не существует
options.bigIntbooleanfalseВозвращать bigint для INTEGER

Методы: db.prepare(sql), db.exec(sql), db.export(), db.backup(), db.close(), db.serialize(), db.transaction(), db.aggregate(), db.loadExtension(), db.enableDefensive().

3.3 Класс StatementSync

Методы: stmt.run(values){lastInsertRowid, changes}, stmt.get(values) → первая строка, stmt.all(values) → все строки, stmt.iterate(values) → итератор.

// INSERT
const insert = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');
const result = insert.run('Alice', '[email protected]');
console.log(result.lastInsertRowid); // 1

// SELECT одной строки
const user = db.prepare('SELECT * FROM users WHERE id = ?').get(1);

// SELECT всех строк
const allUsers = db.prepare('SELECT * FROM users').all();

// Именованные параметры (префиксы $, @ или :)
const byEmail = db.prepare('SELECT * FROM users WHERE email = $email');
const user = byEmail.get({ $email: '[email protected]' });

3.4 Транзакции и сериализация

// Транзакция (атомарная, автооткат при ошибке)
const insertUser = db.prepare('INSERT INTO users (name, email) VALUES (?, ?)');

const insertUsers = db.transaction((users) => {
  for (const user of users) {
    insertUser.run(user.name, user.email);
  }
});

insertUsers([
  { name: 'Charlie', email: '[email protected]' },
  { name: 'Diana', email: '[email protected]' },
]);

// Сериализация
db.serialize(() => {
  db.exec('INSERT INTO users VALUES (1, "Alice")');
  db.exec('INSERT INTO users VALUES (2, "Bob")');
});

3.5 Бэкап и экспорт

// Бэкап с прогрессом
const db = new DatabaseSync('source.db');
db.backup('backup.db', {
  progress: (remaining, total) => {
    const pct = ((total - remaining) / total * 100).toFixed(2);
    console.log(`Backup: ${pct}%`);
  }
});

// Экспорт всей БД как Uint8Array
const data = db.export();

3.6 Полный пример кода

import { DatabaseSync } from 'node:sqlite';

const db = new DatabaseSync(':memory:');

db.exec(`
  CREATE TABLE projects (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,
    created_at TEXT DEFAULT (datetime('now'))
  );

  CREATE TABLE tasks (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    project_id INTEGER REFERENCES projects(id),
    title TEXT NOT NULL,
    done INTEGER DEFAULT 0
  );
`);

const insertProject = db.prepare('INSERT INTO projects (name) VALUES (?)');
const projectResult = insertProject.run('My Project');
const projectId = projectResult.lastInsertRowid;

const addTasks = db.transaction(() => {
  const insertTask = db.prepare('INSERT INTO tasks (project_id, title) VALUES (?, ?)');
  insertTask.run(projectId, 'Спроектировать схему БД');
  insertTask.run(projectId, 'Написать API-эндпоинты');
  insertTask.run(projectId, 'Протестировать приложение');
});
addTasks();

const tasks = db.prepare(`
  SELECT t.id, t.title, t.done, p.name as project
  FROM tasks t
  JOIN projects p ON t.project_id = p.id
  WHERE p.id = ?
`).all(projectId);
console.log(tasks);
db.close();

4. Модель разрешений (Permission Model)

4.1 Обзор и история

Модель разрешений Node.js — это механизм безопасности, ограничивающий доступ процесса Node.js к системным ресурсам.

ВерсияВеха
v20.0.0Экспериментальная, флаг --experimental-permission
v24.0.0Флаг переименован в --permission
v25.0.0Добавлен --allow-net
v26.3.0Стабильная, конфигурационные файлы, process.permission.drop()

4.2 Включение модели разрешений

# Включение модели (ограничивает все разрешения по умолчанию)
node --permission app.js

При включении --permission ограничиваются: доступ к ФС, сеть, дочерние процессы, Worker-потоки, нативные аддоны, WASI, FFI, Inspector-протокол.

4.3 Runtime API: process.permission

// Проверка разрешения
process.permission.has('fs.write');   // true | false
process.permission.has('fs.read', '/home/refs/protected-folder');

// Необратимый отзыв разрешения
process.permission.drop('fs.read', '/etc/myapp');
process.permission.drop('child');

4.4 Разрешения файловой системы

# Разрешить все операции с ФС
node --permission --allow-fs-read=* --allow-fs-write=* index.js

# Разрешить конкретные пути
node --permission --allow-fs-read=/tmp/ --allow-fs-write=/tmp/ index.js

5. FAQ (Часто задаваемые вопросы)

Готова ли нативная поддержка TypeScript в Node.js к production?
Да. Нативная поддержка TypeScript через type stripping стабильна начиная с Node.js 25 (Stability: 2). В Node.js 26 она документирована как "Modules: TypeScript". Весь удаляемый синтаксис — аннотации типов, интерфейсы, дженерики, type aliases — работает без флагов и сторонних инструментов.
Можно ли использовать node:sqlite в production?
Безусловно. Встроенный модуль SQLite стабилен в Node.js 25+ и Active LTS. Поддерживает полный SQL, транзакции, WAL-режим, бэкап и экспорт — без установки npm-пакетов.
В чём разница между node:sqlite и better-sqlite3?
node:sqlite — встроенный модуль: не нужен npm install, не требуется нативная компиляция. better-sqlite3 — внешний npm-пакет, требующий компиляции аддона. Для новых проектов рекомендуется node:sqlite.
Защищает ли модель разрешений от вредоносного кода?
Модель разрешений — это «ремень безопасности»: она предотвращает случайный доступ к ресурсам. Не предназначена для защиты от намеренно вредоносного кода. Для критичных приложений комбинируйте с OS-песочницей (контейнеры, seccomp, AppArmor).
Как включить все три функции вместе?
node --permission --allow-fs-read=/data --allow-fs-write=/data app.ts. Это включает нативный TypeScript, даёт доступ к SQLite через node:sqlite и ограничивает процесс указанными путями.
Нужно ли менять импорты для нативного TypeScript в Node.js?
Да — расширения файлов обязательны. Всегда указывайте .ts: import { config } from './config.ts' (правильно) vs import { config } from './config' (ошибка).
Как модель разрешений работает с node:sqlite?
Модель разрешений может ограничивать доступ к файлам БД. Предоставьте доступ на чтение и запись к путям, где находятся файлы базы: node --permission --allow-fs-read=/data --allow-fs-write=/data app.ts. Без этих разрешений node:sqlite завершится ошибкой ERR_ACCESS_DENIED.

6. Ссылки и дополнительное чтение

Статьи на maximov.by:

Официальная документация:

Нужно создать современное Node.js-приложение с TypeScript, SQLite и правильной безопасностью? Я — full-stack разработчик с глубоким опытом Node.js, TypeScript и production-архитектуры. Обсудим ваш проект.

Контакты

Обсудим ваш проект

Расскажите о вашем проекте — я дам экспертные рекомендации по архитектуре, технологиям и предварительную оценку. Бесплатно.