Types
TypeScript type aliases on the Model namespace
Most public types are namespaced on Model; component prop types are namespaced on Component. Import them from @expressive/mvc:
import type { Model } from '@expressive/mvc';Class shape
Model.Extends<T>
Abstract or concrete constructor of a Model. Use for parameters that accept any class in the hierarchy.
function lookup<T extends Model>(Type: Model.Extends<T>): T | undefined;Model.Type<T>
Concrete (instantiable) constructor. Use when new is required.
function create<T extends Model>(Type: Model.Type<T>): T;Field introspection
Model.Property<T>
Keys of T excluding inherited Model members (get, set, is, etc.). This includes unmanaged _ keys, so it's the key set for overlays like Model.Assign<T> and component props.
Model.Field<T>
Managed keys only - Model.Property<T> without _ keys. Snapshots (Model.Values<T>), ref proxies and instruction keys use this.
class FormState extends Model {
foo = 1;
bar = 'hello';
_handle = null;
}
type Properties = Model.Property<FormState>; // 'foo' | 'bar' | '_handle'
type Fields = Model.Field<FormState>; // 'foo' | 'bar'Model.Event<T>
Any valid event key - includes fields, numbers, symbols, and arbitrary strings for custom events.
type Event<T> = Field<T> | number | symbol | (string & {});Model.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 completednull- destruction
Values and snapshots
Model.Values<T>
All fields with exotic values (child instances, refs, etc.) unwrapped to their inner type.
type Values<T> = { [P in Field<T>]: Export<T[P]> };Model.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 Model.Assign<T>, which preserves declared field types rather than unwrapping them.
Model.Value<T, K>
Single-property lookup type with Export<> unwrapping.
Model.Export<R>
If R is itself a Model, recursively exports Values<R>. Otherwise, if R has a .get(): T method, extracts T. Otherwise returns R. Drives child-instance and ref unwrapping in snapshots.
type Export<R> = R extends Model
? Values<R>
: R extends { get(): infer T }
? T
: R;Constructor args
Model.Args<T>
Union type accepted by Model.new():
type Args<T> = (Args<T> | Init<T> | Assign<T> | Context | void)[];Arrays are flattened recursively at runtime. A Context claims the home - the first one wins, unless the instance was already placed.
Model.Init<T>
A lifecycle callback passed to Model.new(). Can return cleanup, object (assign), or array (recurse).
type Init<T> = (
this: T,
thisArg: T
) => Promise<void> | (() => void) | Args<T> | Assign<T> | void;Model.On<T>
Handler object accepted by Model.on() - hooks lifecycle by stage.
interface On<T> {
type?(type: Model.Extends<T>): void;
setup?(this: T, self: T): void | (() => void) | Promise<void> | Args<T> | Assign<T>;
ready?(this: T, self: T): void | (() => void);
method?(this: T, key: string, fn: Function, self: T): void;
catch?(
this: T,
error: unknown,
kind: 'effect' | 'getter' | 'setup' | 'dead' | 'unused',
key?: string
): unknown;
}Stage timing is covered under Model.on; catch kinds under Error handling.
Model.Ref<T>
The exotic value a ref() field holds - callable to assign, with the value on current:
type Ref<T = any> = {
(next: T): void;
current: T | null;
};Model.Assign<T>
Object overlay type. Maps each field to its value type, preserving method this.
type Assign<T> = Record<string, unknown> & {
[K in Property<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 WhatAssignchecks.
Callbacks
Model.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.
Model.Effect<T>
type Effect<T, R = EffectCallback | Promise<void> | null | void> = (
this: T,
current: T,
update: readonly Event<T>[] | undefined
) => R;
type EffectCallback = (update: boolean | null) => void;Model.Release<R>
type Release<R = void> = (() => void) & PromiseLike<R>;Returned by get(effect). Call to stop the effect; await to stop it once it settles and receive the latest run's value. A sync effect returns its cleanup, so only an async effect resolves a value.
Model.Setter<T>
type Setter<T> = (value: T, previous: T) => T | void;Descriptors
Model.Apply<T>
Property descriptor config for set(key, config) and def factories:
type Apply<T> = {
value?: T;
get?: ((source: Model) => T) | boolean;
set?: Setter<T> | boolean;
enumerable?: boolean;
};Model.Define<T, K>
Type-safe variant of Apply used by set(key, config) - enforces T[K] when K is a known field.
Updated
Model.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: Model;
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 Model> =
{ [P in Model.Field<T>]-?: ref.Object<T[P]> } & { get(): T };
type ref.CustomProxy<T extends Model, R> =
{ [P in Model.Field<T>]-?: R } & { get(): T };Component
Component.Node
The host's element type - ReactNode once @expressive/react is loaded. With no host loaded it is any, so an un-annotated render() in a host-agnostic package still type-checks as JSX.
Component.ModelProps<T>
Every settable field of the class (getters and readonly excluded), each optional - the attributes a parent may assign on every render.
Component.BaseProps<T>
The special props: is ((instance: T) => Model.Assign<T> | void, run once; a returned object is assigned), fallback (Component.Node, or false to defer to an ancestor boundary) and catch ((error, instance) => Promise<void> | void).
Component.RenderProps<R>
The props a render(props) declaration adds - its parameter type when one is declared, else { children?: Component.Node }.
Component.Props<T>
The full JSX prop type for a Component subclass. Combines:
- Model fields (optional)
render(props)declared props (optional or required as declared), orchildrenwhenrenderdeclares noneis,fallbackandcatchspecial props