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.