Native class API
extends, super, getters, setters, private fields. Real inheritance, encapsulation and polymorphism, all reactive.


Native TypeScript classes become fine-grained Vue 3 state. No proxy per instance. No decorators. No component coupling. Nothing paid until first access.
watchwaiting for the first changeReactive() class instance, running the same 1 kB engine that ships. Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
Antoine de Saint-Exupéry
Each of these sank earlier class-reactivity attempts. Solving one or two is easy. ivue ships all of them as one coherent design.
this.method is always correct, always the same reference. The wrapper-arrow era ends.
Deep super.x.value chains resolve level-safe. Reactivity flows through every layer.
The same class identity, direct method binding, and engine branches run in development and production.
The namespace pattern resolves mutual references in any load order.
Ref-returning getters type as writable. Instances are fully inferred.
$watch scopes per instance, $stopEffects cleans up. Pure data pays nothing.
Derivations are shared prototype getters, not per-instance allocations.
Reads hoist to native ref speed with one line where it matters.
Reactive() transforms a class once — the prototype, not the instances. Ref-getters become state, created on first touch. Plain getters re-derive on every read, reactive with zero allocation. Methods bind once, to the right this. Instances stay ordinary objects: a plain new, no proxy, nothing paid until first access.
Everything else falls out of that one move — inheritance, development parity, deterministic teardown, speed. Not features bolted on; consequences of where things live.
import { Reactive } from 'ivue'
import { ref } from 'vue'
class $Cart {
get items() {
return ref<{ price: number }[]>([])
}
get total() {
return this.items.value.reduce((sum, item) => sum + item.price, 0)
}
add(price: number) {
this.items.value.push({ price })
}
}
export namespace Cart {
export const $Class = $Cart // raw — children `extends` this
export let Class = Reactive($Class) // reactive — you `new` this
export type Instance = typeof Class.Instance // expose & reactive() interop
}
const cart = new Cart.Class()Measured, not promised.
ivue vs the World → — ivue against the alternatives, head to head.
Performance by Design → — method and full tables.
Interactive Benchmarks → — five live benchmarks, running in your browser.
Best measured result among fully reactive implementations. Non-reactive controls mark the floor.
| time | ivue is | |
|---|---|---|
ivue new Class() | 21.7 ms | the baseline |
| composable factory | 139 ms | 6.4× faster |
native reactive() | 470 ms | 22× faster |
| eager class engine (unreleased v1) | 2,861 ms | 132× faster |
Refs and computeds do not exist until first access. Median of runs with every instance retained.
| per live instance | 100k total | |
|---|---|---|
| ivue class, 30 getters | 3.7 KB | 364 MB |
| composable, 30 closures | 8.0 KB | 781 MB |
reactive(), fields + getters | 10.4 KB | 1.02 GB |
| composable, 30 computeds | 19.7 KB | 1.93 GB |
Every instance observed by its own effect — live, not at-rest. Derivations live on the prototype; they weigh nothing per instance.
The standard uses raw instances. Measured on Node 22, V8 and Vue 3.5 over 10-million-iteration loops, ordinary ivue access stays below both proxy alternatives:
| access path | ivue raw | shallow proxy | reactive() |
|---|---|---|---|
| plain derived getter | 23.4 ns | 68.2 ns | 125.1 ns |
| ref-getter access | 9.6 ns | 47.0 ns | 72.4 ns |
| method access | 3.8 ns | 42.3 ns | 68.5 ns |
A direct closure ref remains faster than a dotted property read. Stable ivue refs and methods hoist once outside a hot loop, reducing repeated access to the same direct-handle path.
A stress test at document scale: a spreadsheet grid where every cell is live, formula-capable reactive state — built four ways, then weighed.
| bytes/cell | what the cell is | |
|---|---|---|
| composable (idiomatic Vue) | ~758 | closures + eager ref/computeds |
| ivue instance grid | ~67 | plain object + lazy overlay |
| plain JavaScript object, no reactivity | ~40 | { row, col, raw } |
| ivue flyweight columnar | 4.7 | 1 B kind + 8 B Float64, shared |
Measured end-to-end on live grids up to 20,000,000 cells — fully reactive at 8.5× below the plain-object floor. The receipts run in your browser: Interactive Benchmarks →