// recursion budget // // Self-referential type helpers (`Accessed`, `Resolved`, `ResolvedDeep`) // would instantiate forever when given a broad union like `JSX.Element` // (which contains `(() => Element)` and `Element[]`). They carry a // depth budget `D` and stop expanding once it reaches the limit; the // remaining type is left as-is. Centralising these three aliases means // the tuple shape, the increment, and the limit live in one place. type Budget = 0[] type Bump = [0, ...D] type AtLimit = D['length'] extends 50 ? true : false // accessor type Accessor = (() => Accessor) | SignalAccessor | T type Accessed = AtLimit extends true ? T : T extends PromiseLike ? Accessed> : T extends Derived ? Accessed> : T extends DerivedSignal ? Accessed> : T extends SignalAccessor ? Accessed> : T extends SignalFunction ? Accessed> : T extends { (): infer R } ? Accessed> : T type Attribute = | (() => Attribute) | PromiseLike> | SignalAccessor | T /** * Result of recursively invoking functions and flattening nested * arrays — mirrors the runtime behavior of `unwrap`/`resolve`. */ type Resolved = AtLimit extends true ? T : T extends readonly (infer U)[] ? Array>> : T extends () => infer R ? Resolved> : T type ResolvedDeep = AtLimit extends true ? T : T extends readonly (infer U)[] ? ResolvedDeep> : T extends () => infer R ? ResolvedDeep> : T // dom type DOMElement = HTMLElement | SVGElement | MathMLElement // signal type SignalAccessor = () => T /** * Replaces the signal value as-is — does **not** receive the previous * value. To compute from the previous value, use `SignalUpdate`. */ type SignalSetter = (newValue?: T) => SignalChanged type SignalUpdate = ( updateFunction: (prevValue: T) => T, ) => SignalChanged // signal as object/function type Signal = { readonly read: SignalAccessor readonly write: SignalSetter readonly update: SignalUpdate } interface SignalFunction { (value: T): SignalChanged (): T } // signal properties type SignalOptions = | { equals?: false | ((a: T, b: T) => boolean) } | undefined type SignalChanged = boolean // effect / root / on / syncEffect /** * Options accepted by `effect`, `syncEffect`, `root`, and `on`. * Currently accepts no user-facing fields; the runtime passes the * object to the underlying `Computation` base class. Typed with * `Record` (not `{}`) to reject arbitrary properties — * prevents accidental overrides of internal `Computation` fields like * `state`, `fn`, or `updatedAt` while leaving a named anchor for * future options. */ type EffectOptions = undefined | Record // derived type DerivedSignal = { (value: R | (() => R) | PromiseLike): SignalChanged (): R resolved: SignalAccessor } type Derived = DerivedSignal & PromiseLike> // props type When = Accessor type Each = Accessor> // the matched part of a `when` value handed to a `Show`/`Match` // render-prop child. The branch runs only when `when` is truthy, so // the no-match sentinels (`false`/`null`/`undefined`) are removed — // but genuine values stay, including the falsy literals `0`/`''`/`0n` // (a numeric `when` still hands the child a number) type Matched = Exclude // tests type Expect = { toBe: (expected: unknown) => Promise toEqual: (expected: unknown) => Promise toInclude: (expected: unknown) => Promise toThrow: (expected: unknown) => Promise toMatch: (expected: unknown) => Promise not: { toBe: (expected: unknown) => Promise toEqual: (expected: unknown) => Promise toInclude: (expected: unknown) => Promise toThrow: (expected: unknown) => Promise toMatch: (expected: unknown) => Promise } } // utils type Merge = Omit & B