Skip to content

Type utilities

TypeScript-only exports — zero runtime cost. Import as types:

import type {
Path, PathValue,
DeepPartial, DeepRequired, DeepReadonly, DeepMutable,
Prettify, UnionToIntersection, Branded,
Nullable, Maybe, Awaitable, NonEmptyArray,
GenericObject, AlphaNumeric, Primitive,
} from "@mongez/reinforcements";

Dot-notation paths

type Path<T, Depth = 6> // union of every legal dot-notation path
type PathValue<T, P extends string> // resolved value type at path P
type User = {
id: number;
profile: { email: string; addresses: { city: string }[] };
};
type UserPath = Path<User>;
// "id" | "profile" | "profile.email" | "profile.addresses" | "profile.addresses.${number}" | ...
type Email = PathValue<User, "profile.email">; // string
type City = PathValue<User, "profile.addresses.0.city">; // string

Used internally to type get(obj, path) overloads.

Recursive transforms

type DeepPartial<T> // all properties (recursively) optional
type DeepRequired<T> // all properties (recursively) required
type DeepReadonly<T> // all properties (recursively) readonly
type DeepMutable<T> // strips readonly recursively

Each preserves primitives, Date, RegExp, Function, Map<K,V>, and Set<T> rather than recursing into them.

type Config = { api: { url: string; retries: number } };
type DraftConfig = DeepPartial<Config>;
// { api?: { url?: string; retries?: number } }
type FrozenConfig = DeepReadonly<Config>;
// { readonly api: { readonly url: string; readonly retries: number } }

Display & combinators

type Prettify<T> // flatten intersections in hover tooltips
type UnionToIntersection<U> // U union → I intersection (variadic typings)
type Combined = Prettify<{ a: 1 } & { b: 2 }>;
// hovers as { a: 1; b: 2 } instead of { a: 1 } & { b: 2 }

Nominal types

type Branded<T, B extends string> = T & { readonly __brand: B }

Distinguish lookalike primitives at the type level.

type UserId = Branded<string, "UserId">;
type Email = Branded<string, "Email">;
declare function getUser(id: UserId): User;
const id = "abc" as UserId;
getUser(id); // ok
getUser("abc"); // ❌ TS error — string is not assignable to UserId

Common aliases

type Nullable<T> = T | null
type Maybe<T> = T | null | undefined
type Awaitable<T> = T | Promise<T>
type NonEmptyArray<T> = [T, ...T[]]
type GenericObject<T=any> = Record<string, T>
type AlphaNumeric = string | number
type Primitive = AlphaNumeric | boolean
function init(input: Awaitable<Config>): Promise<void> { ... }
function first<T>(arr: NonEmptyArray<T>): T {
return arr[0]; // safe, no `| undefined`
}