Utilities to derive the state, args, deps, and instance shapes of a container class without hand-writing them, plus branded-ID helpers for nominal instance-identity strings. All re-exported from @blac/core (source: types/utilities and types/branded). For a task-oriented walkthrough (generics, inference, typing select) see TypeScript.
A StateContainer (and Cubit) carries three type parameters — S (state), Args (serializable construction/identity data), Deps (injected handles) — extracted from a container class (e.g. typeof CounterCubit), not an instance.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
new (...args: any[]) => StateContainer<S, any, any>
Minimal constructor constraint, parameterized by state. No static registry methods.
A helper that only needs “some container class”.
BlocInstanceType<T>
T extends abstract new (...args: any) => infer R ? R : any
Abstract-aware sibling of TS’s built-in InstanceType<T> (which rejects abstract constructors like Cubit/StateContainer).
”The instance type of this class” when the class is abstract.
BlocConstructor<S, T>
(new (...args: any[]) => InstanceType<T>) & { keepAlive?: boolean }
A constructor type with an optional keepAlive static flag. acquire/borrow/ensure/release are standalone functions, not static methods — this type carries no registry surface. Note: the keepAlive field looks unused in practice — isKeepAliveClass reads the class’s static prop directly, not this type field.
Rare; prefer StateContainerConstructor unless you specifically need the keepAlive field.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
Cubit<S> is a StateContainer<S> with emit / patch exposed as
public mutation surface. Today it adds nothing structurally beyond
StateContainer — both are inherited from the underlying
StructuralContainer<S>. Kept as a real class (not a type alias) because
downstream code does instance instanceof Cubit checks.
The class body is intentionally empty: a no-op emit override would
still go through applyState, and patch is inherited from
StructuralContainer (path-diffed, microtask-flushed). A caller that
wants "skip if no real change" patch semantics can wrap patch
themselves or call emit after a manual equality check.
BlaC tags instance-identity strings with a compile-time-only brand so a plain string can’t be passed where a specific branded ID is expected. No runtime footprint — branded values are just strings at runtime.
Export
Signature
What it’s for
Where you’d use it
Brand<T, B>
T & { [brand]: B }
General nominal-typing helper — two Brands with different B are incompatible even when T is identical.
Rolling your own branded primitive type.
BrandedId<B>
Brand<string, B>
Convenience alias for branding a string.
Any string-ID type you want to brand.
InstanceId
Brand<string, 'InstanceId'>
The branded type BlaC’s registry/identity APIs accept and return instead of a bare string.
Typing a parameter that must be an instance ID, not an arbitrary string.
instanceId(id)
(id: string) => InstanceId
Value-level helper that brands a plain string — a pure runtime cast (returns the input unchanged).
Producing an InstanceId without writing as InstanceId yourself.
import{
functioninstanceId(id: string): InstanceId
Create a branded InstanceId from a string
@param ― id - The string ID to brand
@returns ― Branded InstanceId
instanceId}from'@blac/core';
importtype{
typeInstanceId=string&{
[brand]:"InstanceId";
}
Branded string type for state container instance IDs
InstanceId}from'@blac/core';
declarefunction
functionlookup(id: InstanceId): void
lookup(
id:InstanceId
id:
typeInstanceId=string&{
[brand]:"InstanceId";
}
Branded string type for state container instance IDs
InstanceId): void;
functionlookup(id: InstanceId): void
lookup(
functioninstanceId(id: string): InstanceId
Create a branded InstanceId from a string
@param ― id - The string ID to brand
@returns ― Branded InstanceId
instanceId('user-42'));// ok
functionlookup(id: InstanceId): void
lookup('user-42');// plain string rejected
Error ts(2345) ― Argument of type 'string' is not assignable to parameter of type 'InstanceId'.
Type 'string' is not assignable to type '{ [brand]: "InstanceId"; }'.