Expressive MVC
API Reference

Types

TypeScript type aliases on the State namespace

Most public types are namespaced on State; component prop types are namespaced on Component. Import from @expressive/mvc or @expressive/react:

import type { State } from '@expressive/react';

Class shape

State.Extends<T>

Abstract or concrete constructor of a State. Use for parameters that accept any class in the hierarchy.

function lookup<T extends State>(Type: State.Extends<T>): T | undefined;

State.Type<T>

Concrete (instantiable) constructor. Use when new is required.

function create<T extends State>(Type: State.Type<T>): T;

Field introspection

State.Field<T>

Keys of T excluding inherited State members (get, set, is, etc.).

class MyState extends State {
  foo = 1;
  bar = 'hello';
}

type Fields = State.Field<MyState>; // 'foo' | 'bar'

State.Event<T>

Any valid event key - includes fields, numbers, symbols, and arbitrary strings for custom events.

type Event<T> = Field<T> | number | symbol | (string & {});

State.Signal<T>

All event signals dispatched to listeners, including lifecycle meta events.

type Signal<T> = Event<T> | true | false | null;

Meaning of special values:

  • true - initial activation (ready)
  • false - a normal update flush completed
  • null - destruction

Values and snapshots

State.Values<T>

All fields with exotic values (child states, refs, etc.) unwrapped to their inner type.

type Values<T> = { [P in Field<T>]: Export<T[P]> };

State.Partial<T>

Object compatible with Values<T> - every key optional, Export-unwrapped.

type Partial<T> = { [P in Field<T>]?: Export<T[P]> };

Not currently used by any public signature - set(assign) takes State.Assign<T>, which preserves declared field types rather than unwrapping them.

State.Value<T, K>

Single-property lookup type with Export<> unwrapping.

State.Export<R>

If R is itself a State, recursively exports Values<R>. Otherwise, if R has a .get(): T method, extracts T. Otherwise returns R. Drives child-state and ref unwrapping in snapshots.

type Export<R> = R extends State
  ? Values<R>
  : R extends { get(): infer T }
  ? T
  : R;

Constructor args

State.Args<T>

Union type accepted by State.new() and State.use():

type Args<T> = (Args<T> | Init<T> | Assign<T> | void)[];

Arrays are flattened recursively at runtime.

State.Init<T>

A lifecycle callback passed to State.new(). Can return cleanup, object (assign), or array (recurse).

type Init<T> = (
  this: T,
  thisArg: T
) => Promise<void> | (() => void) | Args<T> | Assign<T> | void;

State.On<T>

Handler object accepted by State.on() - hooks lifecycle by phase. A bare Init function passed to on is sugar for { before }.

interface On<T> {
  type?(type: State.Extends<T>): void;
  before?(this: T, thisArg: T): void | (() => void) | Promise<void> | Args<T> | Assign<T>;
  after?(this: T, self: T): void | (() => void);
}

Phase timing is covered under State.on.

State.Assign<T>

Object overlay type. Maps each field to its value type, preserving method this.

type Assign<T> = Record<string, unknown> & {
  [K in Field<T>]?: T[K] extends (...args: infer A) => infer R
    ? (this: T, ...args: A) => R
    : T[K];
};

The Record<string, unknown> intersection means unknown keys pass the type-checker (they're ignored at runtime) - value-correctness of declared fields is the only check. See What Assign checks.


Callbacks

State.OnEvent<T>

type OnEvent<T> = (
  this: T,
  key: Signal<T>,
  source: T
) => void | (() => void) | null;

Return a function for a deduped settle callback. Return null to auto-unsubscribe.

State.Effect<T>

type Effect<T> = (
  this: T,
  current: T,
  update: readonly Event<T>[] | undefined
) => EffectCallback | Promise<void> | null | void;

type EffectCallback = (update: boolean | null) => void;

State.Setter<T>

type Setter<T> = (value: T, previous: T) => T | void;

Descriptors

State.Apply<T>

Property descriptor config for set(key, config) and def factories:

type Apply<T> = {
  value?: T;
  get?: ((source: State) => T) | boolean;
  set?: Setter<T> | boolean;
  enumerable?: boolean;
};

State.Define<T, K>

Type-safe variant of Apply used by set(key, config) - enforces T[K] when K is a known field.


Updated

State.Updated<T>

type Updated<T> = readonly Event<T>[] & PromiseLike<readonly Event<T>[]>;

Returned by set() - a synchronously readable array of keys updated, awaitable to wait for batch settlement.


Refs

ref.Object<T>

interface ref.Object<T> {
  (value: T | null): void;
  current: T;
  is: State;
  key: string;
  get(): T | null;
  get(callback: (v: T) => void): () => void;
}

ref.Proxy<T> and ref.CustomProxy<T, R>

Produced by ref(this) and ref(this, mapFn) respectively.

type ref.Proxy<T extends State> =
  { [P in State.Field<T>]-?: ref.Object<T[P]> } & { get(): T };

type ref.CustomProxy<T extends State, R> =
  { [P in State.Field<T>]-?: R } & { get(): T };

Component

Component.Props<T>

The full JSX prop type for a Component subclass. Combines:

  • State fields (optional)
  • render(props) declared props (optional or required as declared)
  • is and fallback special props

On this page