Skip to content

Promise

The promise utility wraps any native Promise, executor function, or ReactivePromise into a ComputedPromise β€” an object that is both awaitable like a regular promise and reactive like a signal.

Basic Usage

import {
function promise<T, E = unknown>(p: ReactivePromise<T>): ComputedPromise<T, E> (+2 overloads)

Wraps a promise, executor, or ReactivePromise into a ComputedPromise β€” an object that is both awaitable like a regular Promise and reactive like a Computed signal.

Awaitable: await promise(fetch(...)) resolves to the fulfilled value, or rejects with the rejection reason, just like a native Promise.

Reactive: calling the returned value as a function (cp()) reads the current result inside an effect or computed, tracking it as a dependency. Equivalent to .result β€” returns undefined while pending, the fulfilled value when resolved, or the rejection reason when rejected.

Reactive state is also accessible via:

  • .state β€” "pending" | "fulfilled" | "rejected"
  • .value β€” the resolved value (or undefined while pending)
  • .reason β€” the rejection reason (or undefined while pending/fulfilled)
  • .result β€” T | E | undefined; the resolved value, rejection reason, or undefined while pending

promise
} from "elements-kit/utilities/promise";
// From an executor
const
const cp: ComputedPromise<number, unknown>
cp
=
promise<number, unknown>(executor: Executor<number, unknown>): ComputedPromise<number, unknown> (+2 overloads)

Wraps a promise, executor, or ReactivePromise into a ComputedPromise β€” an object that is both awaitable like a regular Promise and reactive like a Computed signal.

Awaitable: await promise(fetch(...)) resolves to the fulfilled value, or rejects with the rejection reason, just like a native Promise.

Reactive: calling the returned value as a function (cp()) reads the current result inside an effect or computed, tracking it as a dependency. Equivalent to .result β€” returns undefined while pending, the fulfilled value when resolved, or the rejection reason when rejected.

Reactive state is also accessible via:

  • .state β€” "pending" | "fulfilled" | "rejected"
  • .value β€” the resolved value (or undefined while pending)
  • .reason β€” the rejection reason (or undefined while pending/fulfilled)
  • .result β€” T | E | undefined; the resolved value, rejection reason, or undefined while pending

promise
<number>((
resolve: (value: number | PromiseLike<number>) => void
resolve
) => {
function setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number
setTimeout
(() =>
resolve: (value: number | PromiseLike<number>) => void
resolve
(42), 1000);
});
// From an existing Promise
const
const cp2: ComputedPromise<any, unknown>
cp2
=
promise<any, unknown>(p: Promise<any>): ComputedPromise<any, unknown> (+2 overloads)

Wraps a promise, executor, or ReactivePromise into a ComputedPromise β€” an object that is both awaitable like a regular Promise and reactive like a Computed signal.

Awaitable: await promise(fetch(...)) resolves to the fulfilled value, or rejects with the rejection reason, just like a native Promise.

Reactive: calling the returned value as a function (cp()) reads the current result inside an effect or computed, tracking it as a dependency. Equivalent to .result β€” returns undefined while pending, the fulfilled value when resolved, or the rejection reason when rejected.

Reactive state is also accessible via:

  • .state β€” "pending" | "fulfilled" | "rejected"
  • .value β€” the resolved value (or undefined while pending)
  • .reason β€” the rejection reason (or undefined while pending/fulfilled)
  • .result β€” T | E | undefined; the resolved value, rejection reason, or undefined while pending

promise
(
function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
fetch
("/api/data").
Promise<Response>.then<any, never>(onfulfilled?: ((value: Response) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<any>

Attaches callbacks for the resolution and/or rejection of the Promise.

@param ― onfulfilled The callback to execute when the Promise is resolved.

@param ― onrejected The callback to execute when the Promise is rejected.

@returns ― A Promise for the completion of which ever callback is executed.

then
(
res: Response
res
=>
res: Response
res
.
Body.json(): Promise<any>
json
()));

Awaitable

A ComputedPromise is a real Promise β€” you can await it, chain .then() / .catch() / .finally(), and use it anywhere a Promise is expected:

const data = await cp;
cp.then(value => console.log(value))
.catch(err => console.error(err));

Reactive

Calling the ComputedPromise as a function inside an effect or computed tracks it as a reactive dependency:

  • Pending β†’ returns undefined
  • Fulfilled β†’ returns the resolved value
  • Rejected β†’ throws the rejection reason
import { effect } from "elements-kit/signals";
effect(() => {
try {
const value = cp(); // undefined while pending, T when fulfilled
console.log("value:", value);
} catch (err) {
console.error("error:", err);
}
});

State Properties

All three state properties are reactive β€” reading them inside an effect or computed subscribes to changes:

cp.state; // "pending" | "fulfilled" | "rejected"
cp.value; // T | undefined
cp.reason; // E | undefined

Result

.result is a convenience property that returns T | E | undefined β€” the resolved value when fulfilled, the rejection reason when rejected, or undefined while pending. Useful when you don’t need to distinguish between fulfilled and rejected but just want the current value:

effect(() => {
console.log("current result:", cp.result);
});

ReactivePromise

ReactivePromise is the lower-level class that powers ComputedPromise. Use it directly when you need to construct or wrap a promise and expose its reactive state without the Computed callable interface:

import {
class ReactivePromise<T, E = unknown>

A Promise subclass that exposes its state as reactive signals.

Prefer the

promise

factory for most use cases β€” it returns a ComputedPromise that is both awaitable and callable as a signal. Use ReactivePromise directly when you need the lower-level class β€” for example, to wrap a promise and expose .state, .value, .reason, and .result without the Computed callable interface.

@example

const rp = ReactivePromise.from(fetch("/api/data"));
effect(() => {
if (rp.state === "fulfilled") console.log(rp.value);
});

ReactivePromise
} from "elements-kit/utilities/promise";
// From an executor
const
const rp: ReactivePromise<number, unknown>
rp
= new
new ReactivePromise<number, unknown>(executor: (resolve: (value: number | PromiseLike<number>) => void, reject: (reason?: any) => void) => void): ReactivePromise<number, unknown>

A Promise subclass that exposes its state as reactive signals.

Prefer the

promise

factory for most use cases β€” it returns a ComputedPromise that is both awaitable and callable as a signal. Use ReactivePromise directly when you need the lower-level class β€” for example, to wrap a promise and expose .state, .value, .reason, and .result without the Computed callable interface.

@example

const rp = ReactivePromise.from(fetch("/api/data"));
effect(() => {
if (rp.state === "fulfilled") console.log(rp.value);
});

ReactivePromise
<number>((
resolve: (value: number | PromiseLike<number>) => void
resolve
,
reject: (reason?: any) => void
reject
) => {
function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
fetch
("/api/data")
.
Promise<Response>.then<any, never>(onfulfilled?: ((value: Response) => any) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<any>

Attaches callbacks for the resolution and/or rejection of the Promise.

@param ― onfulfilled The callback to execute when the Promise is resolved.

@param ― onrejected The callback to execute when the Promise is rejected.

@returns ― A Promise for the completion of which ever callback is executed.

then
(
res: Response
res
=>
res: Response
res
.
Body.json(): Promise<any>
json
())
.
Promise<any>.then<void, never>(onfulfilled?: ((value: any) => void | PromiseLike<void>) | null | undefined, onrejected?: ((reason: any) => PromiseLike<never>) | null | undefined): Promise<void>

Attaches callbacks for the resolution and/or rejection of the Promise.

@param ― onfulfilled The callback to execute when the Promise is resolved.

@param ― onrejected The callback to execute when the Promise is rejected.

@returns ― A Promise for the completion of which ever callback is executed.

then
(
resolve: (value: number | PromiseLike<number>) => void
resolve
)
.
Promise<void>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>

Attaches a callback for only the rejection of the Promise.

@param ― onrejected The callback to execute when the Promise is rejected.

@returns ― A Promise for the completion of the callback.

catch
(
reject: (reason?: any) => void
reject
);
});
// Wrap an existing promise
const
const rp2: ReactivePromise<Response, unknown>
rp2
=
class ReactivePromise<T, E = unknown>

A Promise subclass that exposes its state as reactive signals.

Prefer the

promise

factory for most use cases β€” it returns a ComputedPromise that is both awaitable and callable as a signal. Use ReactivePromise directly when you need the lower-level class β€” for example, to wrap a promise and expose .state, .value, .reason, and .result without the Computed callable interface.

@example

const rp = ReactivePromise.from(fetch("/api/data"));
effect(() => {
if (rp.state === "fulfilled") console.log(rp.value);
});

ReactivePromise
.
ReactivePromise<T, E = unknown>.from<Response, unknown>(p: Promise<Response>): ReactivePromise<Response, unknown>
from
(
function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
fetch
("/api/data"));
const rp: ReactivePromise<number, unknown>
rp
.
ReactivePromise<number, unknown>.state: "pending" | "fulfilled" | "rejected"
state
; // "pending" | "fulfilled" | "rejected"
const rp: ReactivePromise<number, unknown>
rp
.
ReactivePromise<number, unknown>.value: number | undefined
value
; // T | undefined
const rp: ReactivePromise<number, unknown>
rp
.
ReactivePromise<number, unknown>.reason: unknown
reason
; // E | undefined
const rp: ReactivePromise<number, unknown>
rp
.
ReactivePromise<number, unknown>.result: unknown
result
; // PromiseResult<T, E>

cp instanceof ReactivePromise returns true for any ComputedPromise.

See also