ensureUnique()
Retry generation against your own store until a free ID is found — a hard uniqueness guarantee, without state in the library.
Signature
function ensureUnique<T extends string>(
generate: () => T,
exists: (candidate: T) => boolean | Promise<boolean>,
options?: { maxAttempts?: number } // default: 5
): Promise<T>Why
Random IDs are collision-resistant by probability (see Uniqueness & Collisions). When you want a guarantee, check each candidate against your source of truth and regenerate on the astronomically rare clash. ensureUnique runs that loop for you — and preserves the generator's typed return value.
Usage
import { ensureUnique, id } from "prefid";
const userId = await ensureUnique(
() => id("user"),
(candidate) => db.users.exists(candidate),
);
// userId is typed `user_${string}` and confirmed free in your storeconst { ensureUnique, id } = require("prefid");
const userId = await ensureUnique(
() => id("user"),
(candidate) => db.users.exists(candidate),
);
// userId is a unique user_… id, confirmed free in your storeWorks with any store
You supply the exists check, so ensureUnique stays dependency-free and works with any database, cache, or in-memory structure. The check may be synchronous or return a promise.
// Prisma
ensureUnique(() => id("user"), (c) =>
prisma.user.count({ where: { id: c } }).then((n) => n > 0),
);
// Redis
ensureUnique(() => id("user"), (c) => redis.exists(c).then(Boolean));
// A plain Set (tests / demos)
ensureUnique(() => id("user"), (c) => seen.has(c));Parameters
generate— produces a candidate ID, e.g.() => id("user").exists— returnstrueif the candidate is already taken. Sync or async.options.maxAttempts— how many candidates to try before giving up. Defaults to5.
The loop guard
If exists keeps reporting collisions — usually a bug that always returns true — the function throws after maxAttempts instead of looping forever. That turns a hung server into a clear, catchable error.
Returns & errors
- Resolves to a free ID (typed the same as
generate). - Rejects with a
RangeErrorifmaxAttemptsis not a positive integer. - Rejects with an
Errorif no free ID is found withinmaxAttempts.