TS типы и формы объектов V8

Типы TypeScript не совпадают с формами объектов в V8 (hidden classes). TS не различает порядок ключей, а V8 кэширует именно по порядку создания полей. Поэтому "одинаковый" по TS объект может быть быстрым или медленным в рантайме.

Что это / Зачем в TS

Понять, где TS бессилен в плане производительности:

  • Типы стираются при компиляции.
  • Один TS-тип может породить N разных hidden classes в V8.
  • Чтобы код был быстрым — нужно держать в голове форму, а не только тип.

Проблема: TS не выражает форму

type User = { id: number; name: string };

// Оба соответствуют типу User. Для TS они одинаковы.
const a = { id: 1, name: 'A' };
const b = { name: 'B', id: 2 };

// Для V8 — РАЗНЫЕ hidden classes.
// Если массив будет [a, b, a, b, ...] — мегаморфный доступ, deopt.

Что хотел бы автор (недоработка TS)

"Нужна директива class exact / interface exact, фиксирующая порядок полей."

Гипотетический синтаксис:

interface exact User {
  id: number;     // должно быть первым
  name: string;   // должно быть вторым
}

Такой директивы в TS нет. Заменяется code review-конвенцией.

Правила для стабильных форм

1. Всегда возвращай одну форму

// Плохо
function findUser(id: number): User | null {
  const row = db.find(id);
  if (!row) return null;
  return { id: row.id, name: row.name };
}

// Лучше — стабильная форма
type Result = { ok: true; user: User } | { ok: false };
function findUser(id: number): Result {
  // ...
}

2. Не делай delete

const user = { id: 1, name: 'A', email: 'a@a' };
delete (user as any).email; // V8 запоминает удаление, новая hidden class

3. Не меняй порядок полей в фабриках

// Плохо
function make(type: 'admin' | 'user'): User {
  if (type === 'admin') return { role: 'admin', id, name };
  return { id, name, role: 'user' };
}

// Хорошо — единый порядок
function make(type: 'admin' | 'user'): User {
  return { id, name, role: type };
}

4. Всегда присваивай поля, даже null

// Плохо — два разных hidden class
function build(meta?: Meta) {
  if (meta) return { id, name, meta };
  return { id, name };
}

// Хорошо — одна форма
function build(meta?: Meta) {
  return { id, name, meta: meta ?? null };
}

Когда использовать / Когда НЕ

  • ✅ когда: hot path, миллионы вызовов, замеры показывают deopt
  • ✅ когда: однотипные коллекции (массивы записей из БД)
  • ❌ когда: прототипирование — преждевременная оптимизация
  • ❌ когда: разовый код, конфиги, разовые литералы

Альтернативы

  • TypedArrays — для массивов чисел гарантирует фиксированную форму памяти.
  • Map вместо object — если ключи динамические.
  • class с явным constructor — заставляет фиксировать порядок полей.

🎓 Источники

  • 🎓 TypeScript vs JavaScript: как лучше писать типы · 2025-11-08 · YouTube
    • Тезисы: TS не различает порядок полей; формы V8 ≠ типы TS; TS не ускоряет код.
  • 🎓 Я запрещаю UNION types в TypeScript и ORM · 2025-12-17 · YouTube
    • Тезисы: тренируйте формы объектов; не использовать delete; одна форма выхода.
  • 🎓 Производительность JS Объекты в V8 · AsForJS · 2025-02-07 · YouTube
    • V8-runtime angle на формы и hidden classes.

См. также