Promise

Wrap a Promise as a ComputedPromise — awaitable and reactive.

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.

data.tsmain.tsx
import { promise } from "elements-kit/utilities/promise";

export const data = promise<string>((resolve) => {
  setTimeout(() => resolve(`Hello at ${new Date().toLocaleTimeString()}`), 800);
});
main.tsx
import { promise } from "elements-kit/utilities/promise";

test("starts in pending state", () => {
  const p = promise<number>(() => {});
  expect(p.state).toBe("pending");
  expect(p.value).toBeUndefined();
});

test("resolves to fulfilled with value", async () => {
  const p = promise<number>((resolve) => resolve(42));
  await p;
  expect(p.state).toBe("fulfilled");
  expect(p.value).toBe(42);
});

test("rejects to rejected with reason", async () => {
  const p = promise<number>((_, reject) => reject(new Error("nope")));
  await p.catch(() => {});
  expect(p.state).toBe("rejected");
  expect(p.reason).toBeInstanceOf(Error);
});

test("is awaitable like a native Promise", async () => {
  const p = promise<string>((resolve) =>
    setTimeout(() => resolve("ok"), 10),
  );
  const value = await p;
  expect(value).toBe("ok");
});

Basic Usage

import {  } from "elements-kit/utilities/promise";

// From an executor
const  = <number>(() => {
  (() => (42), 1000);
});

// From an existing Promise
const  = (("/api/data").( => .()));

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 {  } from "elements-kit/utilities/promise";

// From an executor
const  = new <number>((, ) => {
  ("/api/data")
    .( => .())
    .()
    .();
});

// Wrap an existing promise
const  = .(("/api/data"));

.;  // "pending" | "fulfilled" | "rejected"
.;  // T | undefined
.; // E | undefined
.; // PromiseResult<T, E>

cp instanceof ReactivePromise returns true for any ComputedPromise.

See also