TypeScript Ergonomics & Branded Types
DaySafe is written in TypeScript from the ground up, featuring branded nominal types, strict type guards, and zero-overhead compile-time guarantees.
The DateOnly Branded Type
In TypeScript, a primitive string can contain anything: "2026-11-02", "invalid-string", or an arbitrary uuid.
DaySafe introduces a nominal branded type, DateOnly, which represents a strictly validated Gregorian calendar date in YYYY-MM-DD format:
400 font-semibold">type DateOnly = string & {400 font-semibold">readonly __brand: 400 font-semibold">class="text-emerald-400">"DateOnly";};
You cannot arbitrarily assign an unvalidated string to a DateOnly variable. It can only be created via parseDate() or narrowed via isValidDate().
Type Narrowing with isValidDate()
isValidDate(input) is a TypeScript type guard (input is DateOnly). Inside any conditional block where it returns true, TypeScript automatically narrows the variable:
400 font-semibold">import { isValidDate, DateOnly } 400 font-semibold">from 400 font-semibold">class="text-emerald-400">"daysafe";400 font-semibold">function processBooking(userInput: unknown) {400 font-semibold">if (isValidDate(userInput)) {// userInput is now typed as DateOnly!400 font-semibold">const validatedDate: DateOnly = userInput;console.log(400 font-semibold">class="text-emerald-400">"Safe date confirmed:", validatedDate);} 400 font-semibold">else {// TypeScript knows userInput is NOT a valid DateOnly400 font-semibold">throw 400 font-semibold">new Error(400 font-semibold">class="text-emerald-400">"Invalid date provided");}}
Complete Exported Types Reference
type DateInput = DateOnly | string
All DaySafe operation arguments accept DateInput, allowing you to pass either branded DateOnly values or literal ISO strings without tedious type casting.
interface DateParts
400 font-semibold">interface DateParts {/** Gregorian year (1 - 9999) */year: number;/** Gregorian month (1 = January, 12 = December) */month: number;/** Day of the month (1 - 31) */day: number;}
interface FormatDateOptions
400 font-semibold">interface FormatDateOptions {locale?: string | string[];style?: 400 font-semibold">class="text-emerald-400">"full" | 400 font-semibold">class="text-emerald-400">"long" | 400 font-semibold">class="text-emerald-400">"medium" | 400 font-semibold">class="text-emerald-400">"short";dateStyle?: 400 font-semibold">class="text-emerald-400">"full" | 400 font-semibold">class="text-emerald-400">"long" | 400 font-semibold">class="text-emerald-400">"medium" | 400 font-semibold">class="text-emerald-400">"short";year?: 400 font-semibold">class="text-emerald-400">"numeric" | 400 font-semibold">class="text-emerald-400">"2-digit";month?: 400 font-semibold">class="text-emerald-400">"numeric" | 400 font-semibold">class="text-emerald-400">"2-digit" | 400 font-semibold">class="text-emerald-400">"long" | 400 font-semibold">class="text-emerald-400">"short" | 400 font-semibold">class="text-emerald-400">"narrow";day?: 400 font-semibold">class="text-emerald-400">"numeric" | 400 font-semibold">class="text-emerald-400">"2-digit";weekday?: 400 font-semibold">class="text-emerald-400">"long" | 400 font-semibold">class="text-emerald-400">"short" | 400 font-semibold">class="text-emerald-400">"narrow";era?: 400 font-semibold">class="text-emerald-400">"long" | 400 font-semibold">class="text-emerald-400">"short" | 400 font-semibold">class="text-emerald-400">"narrow";}
type ComparisonResult = -1 | 0 | 1
Strict 3-way chronological ordering result. Guaranteed to be directly compatible with Array.prototype.sort(compareDates).
Dual ESM & CommonJS Declarations
DaySafe ships with full type definitions for both modern ESM bundlers (dist/index.d.mts) and legacy CommonJS environments (dist/index.d.ts). TypeScript resolve declarations cleanly regardless of whether your project uses "moduleResolution": "NodeNext" or "bundler".