Nominal (branded) TypeScript types & helpers for safe opaque types.
π·οΈπ§©π‘οΈ Type-safe branding for primitives and objects in TypeScript.
See the Usage Guide for practical examples and patterns.
See the API Reference for a summary of all exports and detailed documentation.
pnpm add @variablesoftware/vs-brand-utilsimport {
Brand,
brand,
isBrand,
assertBrand,
unbrand,
createBrand,
brandArray,
unbrandArray,
brandMany
} from "@variablesoftware/vs-brand-utils";
// Define a branded type
export type UserId = Brand<"UserId", string>;
// Brand a value
const id = brand<"UserId", string>("UserId", "abc123");
// Type-safe: cannot assign UserId to string or vice versa
// const s: string = id; // Type error
// const id2: UserId = 'plainstring'; // Type error
// Type guard
if (isBrand("UserId", id)) {
// id is UserId here
}
// Assert
assertBrand("UserId", id);
// Unbrand
const raw: string = unbrand("UserId", id);
// Brand an array
const brandedArr = brandArray("UserId", ["a", "b"]);
// Unbrand an array
const arr: string[] = unbrandArray("UserId", brandedArr);
// Brand many values
const many = brandMany("UserId", "a", "b");
// Factory for a specific brand
const TenantId = createBrand<"TenantId", string>("TenantId");
const tid = TenantId.brand("t-123");- π·οΈ Nominal/opaque types for primitives and objects
- π§© Type-safe branding and unbranding helpers
- π‘οΈ Compile-time enforcement: prevents accidental mixing of branded and unbranded types
- Array helpers for batch branding/unbranding
- Factory for reusable brand helpers
- Zero runtime cost: all checks are type-level
- 100% test and code coverage (see
tests/unit/for split test suites) - Edge-case and runtime safety for all helpers
- Prevent accidental mixing of IDs, tokens, and other primitives
- Enable safe domain modeling with TypeScript
- No runtime overhead or dependencies
- Simple, composable API
- Fully documented and tested
Tested using vitest with coverage for:
- Branding and unbranding
- Type guards and assertions
- Compile-time type errors
- Array helpers
- Edge cases and runtime behaviors
Test suites are organized by concern:
runtime-branding.test.tscompile-type-errors.test.tshelpers-and-factory.test.tsedge-cases.test.tsmissing-marker-edge-cases.test.ts
Run tests:
pnpm testAs of May 2025, the codebase is split into focused modules for maintainability and tree-shaking:
coreβ core types and internal symbolsbrandβ branding helpers (brand,brandArray,brandMany)typeguardsβ type guard helpers (isBrand)assertβ assertion helpers (assertBrand)unbrandβ unbranding helpers (unbrand,unbrandArray)factoryβ thecreateBrandfactory for a bundled API
You can import everything from the main entry point:
import { brand, isBrand, assertBrand, unbrand, createBrand } from "@variablesoftware/vs-brand-utils";Or, for advanced usage and smaller bundles, import only what you need:
import { brand } from "@variablesoftware/vs-brand-utils/brand";
import { isBrand } from "@variablesoftware/vs-brand-utils/typeguards";All helpers are still available via the main package import for convenience.
- All helpers and edge cases are tested for 100% coverage.
- See
src/for the modular implementation. - See
tests/unit/for split test suites by concern.
This package is under active development and not yet stable.
Once stable, it will be published as:
"@variablesoftware/vs-brand-utils": "^0.8.0"MIT Β© Rob Friedman / Variable Software
Built with β€οΈ by @variablesoftware
Thank you for downloading and using this project. Pull requests are warmly welcomed!
- Naming, logging, error messages, and tests avoid cultural or ableist bias
- Avoids assumptions about input/output formats or encodings
- Designed for clarity, predictability, and parity with TypeScript best practices
- Works well in diverse, multilingual, and inclusive developer environments