Scanning database...
Tools
Articles

No matches found for ""

View All Results
Home Dev Lab typescript
Developer Lab

UUID in TypeScript

Production-ready implementation guide with CSPRNG-backed code snippets.



Generate UUID in TypeScript

TypeScript uses the same native crypto.randomUUID() as JavaScript, but adds type safety with branded UUID types, type guards, and Zod validation for incoming IDs.

Quick Reference

Approach Version Type Safe Use Case
crypto.randomUUID() v4 Template literal type General purpose — zero deps, built-in
Branded UUID type any Nominal typing Prevent mixing UserId / OrderId at compile time
z.string().uuid() any Runtime validation Validate UUIDs from API requests / user input
v7 from uuid package v7 Yes Time-ordered database PKs

Primary Implementation

Production Ready
typescript snippet
// TypeScript's built-in type for crypto.randomUUID() return value:
// `${string}-${string}-${string}-${string}-${string}`

// Branded / nominal UUID type — prevents mixing different ID types
type Brand<T, B> = T & { readonly _brand: B };
type UUID = Brand<`${string}-${string}-${string}-${string}-${string}`, 'UUID'>;

// Type-safe UUID factory
function generateUUID(): UUID {
  return crypto.randomUUID() as UUID;
}

// Specific entity ID types — UserId and OrderId are not interchangeable
type UserId  = Brand<UUID, 'UserId'>;
type OrderId = Brand<UUID, 'OrderId'>;

function createUserId():  UserId  { return generateUUID() as UserId; }
function createOrderId(): OrderId { return generateUUID() as OrderId; }

// Type guard for runtime validation
function isUUID(s: string): s is UUID {
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(s);
}

const userId:  UserId  = createUserId();
const orderId: OrderId = createOrderId();

// TypeScript error: Argument of type 'UserId' is not assignable to 'OrderId'
// processOrder(userId); // ← compile-time error

All UUID Versions

UUID v4 — Random (native, no deps)

typescript snippet
// Return type is `${string}-${string}-${string}-${string}-${string}`
const id = crypto.randomUUID();
// → "550e8400-e29b-41d4-a716-446655440000"

UUID v7 — Time-ordered (uuid package)

typescript snippet
// npm install uuid @types/uuid
import { v7 as uuidv7 } from 'uuid';

const id: string = uuidv7();
// → "018e8f6a-1b2c-7d3e-9f4a-5b6c7d8e9f0a"

Zod validation — runtime UUID checking

typescript snippet
// npm install zod
import { z } from 'zod';

const UUIDSchema = z.string().uuid();

// Parse incoming request params
const RequestSchema = z.object({
  userId: z.string().uuid(),
  orderId: z.string().uuid(),
});

function handleRequest(body: unknown) {
  const { userId, orderId } = RequestSchema.parse(body);
  // userId and orderId are validated strings here
}

Real-World Use Cases

1. Typed entity IDs — prevent ID mix-ups at compile time

typescript snippet
type UserId  = string & { readonly _brand: 'UserId' };
type OrderId = string & { readonly _brand: 'OrderId' };

interface User  { id: UserId;  name: string; }
interface Order { id: OrderId; userId: UserId; total: number; }

function getOrder(id: OrderId): Promise<Order> { /* ... */ }

const userId  = crypto.randomUUID() as UserId;
const orderId = crypto.randomUUID() as OrderId;

getOrder(orderId); // ✓ OK
// getOrder(userId); // ✗ TypeScript error — UserId is not OrderId

2. API response typing with UUID fields

typescript snippet
import { z } from 'zod';

// Define the shape of an API response
const ApiResponseSchema = z.object({
  id:        z.string().uuid(),
  createdAt: z.string().datetime(),
  name:      z.string(),
});

type ApiResponse = z.infer<typeof ApiResponseSchema>;

async function fetchItem(id: string): Promise<ApiResponse> {
  const res  = await fetch(`/api/items/${id}`);
  const data = await res.json();
  return ApiResponseSchema.parse(data); // throws if UUID is invalid
}

3. Discriminated union with UUID brands

typescript snippet
type ProductId  = string & { _brand: 'ProductId' };
type CategoryId = string & { _brand: 'CategoryId' };

type EntityRef =
  | { type: 'product';  id: ProductId }
  | { type: 'category'; id: CategoryId };

function resolveEntity(ref: EntityRef) {
  switch (ref.type) {
    case 'product':  return fetchProduct(ref.id);   // id is ProductId
    case 'category': return fetchCategory(ref.id);  // id is CategoryId
  }
}

Common Mistakes

Using string instead of a branded UUID type

Typing all IDs as string means TypeScript can't catch you passing a userId where an orderId is expected. Branded types cost nothing at runtime and prevent entire classes of bugs.

Not validating incoming UUIDs at runtime

TypeScript types are erased at runtime. A UUID coming from an HTTP request is just a string — validate it with z.string().uuid() or a type guard before trusting it.

Forgetting @types/uuid when using the uuid package

The uuid npm package ships its own types since v9, but older versions need npm install --save-dev @types/uuid for TypeScript support.

How It Works

TypeScript's lib.dom.d.ts types crypto.randomUUID() as returning `${string}-${string}-${string}-${string}-${string}` — a template literal type that structurally matches the UUID format.

Branded types add a phantom property (_brand) that only exists in the type system. At runtime, the value is still a plain string — zero overhead.

Output Formats

crypto.randomUUID()

f47ac10b-58cc-4372-a567-0e02b2c3d479

TypeScript inferred type

`${string}-${string}-${string}-${string}-${string}`

Branded type

string & { readonly _brand: 'UserId' }

Best Practices

Create branded types for each entity ID — prevents accidental ID mix-ups at compile time.

Validate incoming UUIDs with Zod at API boundaries — types are erased at runtime.

Use crypto.randomUUID() for v4 — no extra package needed in modern TS projects.

Performance

Same as JavaScript — 5–10 million UUIDs/second natively. TypeScript types are compile-time only and add zero runtime overhead.

Branded types are purely structural — the runtime value is a plain string with no extra properties.

Installation

# No install needed for v4 (built-in)
npm install uuid # v7, v5, v3
npm install zod # runtime validation

The uuid package ships its own TypeScript types since v9. No separate @types/uuid needed.

Security

Entropy source: Same as JavaScript — crypto.randomUUID() uses the OS CSPRNG. Cryptographically secure.

Always validate UUIDs from external sources at runtime — TypeScript types provide no runtime protection against malformed input.

/div>