The complete type toolkit exported from @blac/core. These utilities let you derive the state, args, deps, and instance shapes of a container class without hand-writing them, and the branded-ID helpers give you nominal InstanceId strings. Every signature on this page is quoted verbatim from source.
For a task-oriented walkthrough of typing blocs (generic parameters, inference, common pitfalls) see TypeScript. This page is the reference: one heading per export, the exact signature, what it does, and a small example.
All examples assume this setup, which is hidden from the rendered snippet but type-checked:
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.
A StateContainer (and therefore Cubit) carries three type parameters: S (state), Args (serializable construction/identity data), and Deps (injected non-serializable handles). These utilities pull each one back out of a container class (the constructor, e.g. typeof CounterCubit), so you never have to re-declare a state shape that already lives on the class.
Extracts the state type from a container constructor as a Readonly<S>. This is the type you get back from useBloc and from the state getter — read-only, because state is immutable from the outside. Resolves to never if T is not a container constructor.
type S =
type ExtractState<T> =TextendsStateContainerConstructor<inferSextendsobject> ?Readonly<S> :never
The same as ExtractState, but without the Readonly<> wrapper — the raw S as the class declared it. Reach for this only when you genuinely need a mutable view (for example, building the next state object before you emit it); prefer ExtractState everywhere a value is being read.
type Draft =
type ExtractStateMutable<T> =TextendsStateContainerConstructor<inferSextendsobject> ?S:never
Extracts the Args type — the serializable data a bloc is constructed/identified with (see Passing Inputs). Falls back to void when the class declares no args. Note the match is against a zero-argument constructor shape (new () =>), which is how container subclasses are written.
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<
interface UserState
UserState, {
userId: string
userId:string }> {
constructor() {
super({
UserState.name: string
name: '' });
}
}
type A =
type ExtractArgs<T> =Textendsnew()=>StateContainer<any, inferA, any> ?A:void
Extract the args type (serializable construction/identity data) from a
StateContainer subclass.
@template ― T - The StateContainer constructor type
Extracts the Deps type — the injected non-serializable handles (clients, services, other blocs) a container depends on. Falls back to Record<string, never> (the “no deps” shape) when none are declared.
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<
interface FeedState
FeedState, void, {
api: {
fetch(): void;
}
api: {
functionfetch():void
fetch():void } }> {
constructor() {
super({
FeedState.posts: string[]
posts: [] });
}
}
type D =
type ExtractDeps<T> =Textendsnew()=>StateContainer<any, any, inferD> ?D:Record<string, never>
Extract the deps type (injected non-serializable handles) from a
StateContainer subclass.
@template ― T - The StateContainer constructor type
Extracts the runtime constructor parameter tuple from any class — this is plain TypeScript constructor inference, not BlaC’s Args. Use it when you need the literal constructor(...) parameters of a class. Resolves to never[] for non-constructors.
class
classPoint
Point {
constructor(
public
Point.x: number
x:number,
public
Point.y: number
y:number,
) {}
}
type P =
type ExtractConstructorArgs<T> =Textendsnew(...args:inferP)=>any?P:never[]
These describe the instance a container class produces, and the constructor shape (including the static registry methods like acquire and release) that @blac/core and @blac/react use to type their entry points.
Resolves a constructor type to its instance type, including abstract classes. It is the abstract-aware sibling of TypeScript’s built-in InstanceType<T> (which rejects abstract constructors). Because Cubit and StateContainer are abstract, this is the safe choice for “the instance of this class.”
type
type Instance =CounterCubit
Instance=
type BlocInstanceType<Textendsabstractnew(...args:any)=>any> =Textendsabstractnew(...args:any)=>inferR?R:any
Extract instance type from an abstract class constructor
@template ― T - The abstract class constructor type
A constructor type for a StateContainer subclass, with an optional keepAlive static flag. Any ordinary Cubit / Bloc subclass satisfies BlocConstructor directly. There is no static registry surface on the type itself — acquire, borrow, borrowSafe, ensure, and release are standalone functions imported from @blac/core, not static methods on the class. Their parameter type is the lighter StateContainerConstructor. See Instance Management for what those functions do.
// A helper that only needs "some container class" uses StateContainerConstructor.
// A plain Cubit/Bloc subclass satisfies this directly.
Acquire an instance with ref tracking (ownership semantics). Instance
identity is derived purely from args (via the class's static key(args),
a structural hash of args, or the default sentinel when there are none).
@param ― BlocClass - The StateContainer class constructor
@param ― opts.args - Construction/identity args; derives the instance key
@param ― opts.refId - Named reference ID for debugging; auto-generated if omitted
The instance type of a container class with its state property narrowed to the Readonly state for that class. Useful when you want the full instance (methods, getters) but with a precisely-typed, read-only state.
type
type ReadonlyInstance =Omit<CounterCubit, "state"> & {
state:Readonly<CounterState>;
}
ReadonlyInstance=
type InstanceReadonlyState<TextendsStateContainerConstructor=any> =Omit<InstanceType<T>, "state"> & {
state:ExtractState<T>;
}
InstanceReadonlyState<typeof
classCounterCubit
CounterCubit>;
declare const
const c:ReadonlyInstance
c:
type ReadonlyInstance =Omit<CounterCubit, "state"> & {
Like InstanceReadonlyState, but the state property is the mutableS rather than Readonly<S>. Reach for it only when you specifically need a writable view of state on a typed instance.
type
type MutableInstance =Omit<CounterCubit, "state"> & {
state:CounterState;
}
MutableInstance=
type InstanceState<TextendsStateContainerConstructor=any> =Omit<InstanceType<T>, "state"> & {
A StateContainer instance keyed by its state type S rather than by a concrete class, with state narrowed to Readonly<S>. Use it when you want to describe “any container holding this state shape” without pinning a specific subclass.
The minimal constructor type for a container class, parameterized by state S. It is the constraint the extraction utilities (ExtractState, ExtractStateMutable, InstanceReadonlyState, InstanceState) match against. Unlike BlocConstructor it carries no static registry methods — use it where you only care that something is a container class.
BlaC tags instance-identity strings with a brand so a plain string cannot be passed where an InstanceId is expected. The brand is a compile-time-only phantom property keyed by a unique symbol; it has no runtime footprint — branded values are just strings at runtime.
The general nominal-typing helper: intersects a base type T with a phantom property under a private unique symbol, tagged by the brand identifier B. Two Brands with different B are incompatible even when T is identical, which is what prevents accidental mixing of similar primitive types.
type
type UserId =string& {
[brand]:"UserId";
}
UserId=
type Brand<T, B> =T& {
[brand]:B;
}
Utility type for creating branded/nominal types.
Prevents accidental type confusion between similar primitive types.
@template ― T - The base type
@template ― B - The brand identifier
Brand<string, 'UserId'>;
type
type OrderId =string& {
[brand]:"OrderId";
}
OrderId=
type Brand<T, B> =T& {
[brand]:B;
}
Utility type for creating branded/nominal types.
Prevents accidental type confusion between similar primitive types.
@template ― T - The base type
@template ― B - The brand identifier
Brand<string, 'OrderId'>;
declare const
const u:UserId
u:
type UserId =string& {
[brand]:"UserId";
}
UserId;
declarefunction
functionloadOrder(id:OrderId):void
loadOrder(
id: OrderId
id:
type OrderId =string& {
[brand]:"OrderId";
}
OrderId):void;
functionloadOrder(id:OrderId):void
loadOrder(u);
Error ts(2345) ― Argument of type 'UserId' is not assignable to parameter of type 'OrderId'.
Type 'UserId' is not assignable to type '{ [brand]: "OrderId"; }'.
Types of property '[brand]' are incompatible.
Type '"UserId"' is not assignable to type '"OrderId"'.
The branded string type BlaC uses for state-container instance identities — BrandedId<'InstanceId'> by another name. Registry and identity APIs accept and return this rather than a bare string, so an arbitrary string cannot stand in for an instance key by accident.
declarefunction
functionlookup(id:InstanceId):void
lookup(
id: InstanceId
id:
type InstanceId =string& {
[brand]:"InstanceId";
}
Branded string type for state container instance IDs
InstanceId):void;
functionlookup(id:InstanceId):void
lookup('not-branded');
Error ts(2345) ― Argument of type 'string' is not assignable to parameter of type 'InstanceId'.
Type 'string' is not assignable to type '{ [brand]: "InstanceId"; }'.
The value-level helper that brands a plain string as an InstanceId. It is a pure cast at runtime (returns the input unchanged); its only job is to give you a typed InstanceId to hand to APIs that require one, without writing the as InstanceId assertion yourself.
const
const id:InstanceId
id:
type InstanceId =string& {
[brand]:"InstanceId";
}
Branded string type for state container instance IDs