Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Advanced TypeScript expert covering type-level programming, branded types, monorepos, and migration strategies.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/utility-types.ts
1/**2* TypeScript Utility Types Library3*4* A collection of commonly used utility types for TypeScript projects.5* Copy and use as needed in your projects.6*/78// =============================================================================9// BRANDED TYPES10// =============================================================================1112/**13* Create nominal/branded types to prevent primitive obsession.14*15* @example16* type UserId = Brand<string, 'UserId'>17* type OrderId = Brand<string, 'OrderId'>18*/19export type Brand<K, T> = K & { readonly __brand: T }2021// Branded type constructors22export type UserId = Brand<string, 'UserId'>23export type Email = Brand<string, 'Email'>24export type UUID = Brand<string, 'UUID'>25export type Timestamp = Brand<number, 'Timestamp'>26export type PositiveNumber = Brand<number, 'PositiveNumber'>2728// =============================================================================29// RESULT TYPE (Error Handling)30// =============================================================================3132/**33* Type-safe error handling without exceptions.34*/35export type Result<T, E = Error> =36| { success: true; data: T }37| { success: false; error: E }3839export const ok = <T>(data: T): Result<T, never> => ({40success: true,41data42})4344export const err = <E>(error: E): Result<never, E> => ({45success: false,46error47})4849// =============================================================================50// OPTION TYPE (Nullable Handling)51// =============================================================================5253/**54* Explicit optional value handling.55*/56export type Option<T> = Some<T> | None5758export type Some<T> = { type: 'some'; value: T }59export type None = { type: 'none' }6061export const some = <T>(value: T): Some<T> => ({ type: 'some', value })62export const none: None = { type: 'none' }6364// =============================================================================65// DEEP UTILITIES66// =============================================================================6768/**69* Make all properties deeply readonly.70*/71export type DeepReadonly<T> = T extends (...args: any[]) => any72? T73: T extends object74? { readonly [K in keyof T]: DeepReadonly<T[K]> }75: T7677/**78* Make all properties deeply optional.79*/80export type DeepPartial<T> = T extends object81? { [K in keyof T]?: DeepPartial<T[K]> }82: T8384/**85* Make all properties deeply required.86*/87export type DeepRequired<T> = T extends object88? { [K in keyof T]-?: DeepRequired<T[K]> }89: T9091/**92* Make all properties deeply mutable (remove readonly).93*/94export type DeepMutable<T> = T extends object95? { -readonly [K in keyof T]: DeepMutable<T[K]> }96: T9798// =============================================================================99// OBJECT UTILITIES100// =============================================================================101102/**103* Get keys of object where value matches type.104*/105export type KeysOfType<T, V> = {106[K in keyof T]: T[K] extends V ? K : never107}[keyof T]108109/**110* Pick properties by value type.111*/112export type PickByType<T, V> = Pick<T, KeysOfType<T, V>>113114/**115* Omit properties by value type.116*/117export type OmitByType<T, V> = Omit<T, KeysOfType<T, V>>118119/**120* Make specific keys optional.121*/122export type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>123124/**125* Make specific keys required.126*/127export type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>128129/**130* Make specific keys readonly.131*/132export type ReadonlyBy<T, K extends keyof T> = Omit<T, K> & Readonly<Pick<T, K>>133134/**135* Merge two types (second overrides first).136*/137export type Merge<T, U> = Omit<T, keyof U> & U138139// =============================================================================140// ARRAY UTILITIES141// =============================================================================142143/**144* Get element type from array.145*/146export type ElementOf<T> = T extends (infer E)[] ? E : never147148/**149* Tuple of specific length.150*/151export type Tuple<T, N extends number> = N extends N152? number extends N153? T[]154: _TupleOf<T, N, []>155: never156157type _TupleOf<T, N extends number, R extends unknown[]> = R['length'] extends N158? R159: _TupleOf<T, N, [T, ...R]>160161/**162* Non-empty array.163*/164export type NonEmptyArray<T> = [T, ...T[]]165166/**167* At least N elements.168*/169export type AtLeast<T, N extends number> = [...Tuple<T, N>, ...T[]]170171// =============================================================================172// FUNCTION UTILITIES173// =============================================================================174175/**176* Get function arguments as tuple.177*/178export type Arguments<T> = T extends (...args: infer A) => any ? A : never179180/**181* Get first argument of function.182*/183export type FirstArgument<T> = T extends (first: infer F, ...args: any[]) => any184? F185: never186187/**188* Async version of function.189*/190export type AsyncFunction<T extends (...args: any[]) => any> = (191...args: Parameters<T>192) => Promise<Awaited<ReturnType<T>>>193194/**195* Promisify return type.196*/197export type Promisify<T> = T extends (...args: infer A) => infer R198? (...args: A) => Promise<Awaited<R>>199: never200201// =============================================================================202// STRING UTILITIES203// =============================================================================204205/**206* Split string by delimiter.207*/208export type Split<S extends string, D extends string> =209S extends `${infer T}${D}${infer U}`210? [T, ...Split<U, D>]211: [S]212213/**214* Join tuple to string.215*/216export type Join<T extends string[], D extends string> =217T extends []218? ''219: T extends [infer F extends string]220? F221: T extends [infer F extends string, ...infer R extends string[]]222? `${F}${D}${Join<R, D>}`223: never224225/**226* Path to nested object.227*/228export type PathOf<T, K extends keyof T = keyof T> = K extends string229? T[K] extends object230? K | `${K}.${PathOf<T[K]>}`231: K232: never233234// =============================================================================235// UNION UTILITIES236// =============================================================================237238/**239* Last element of union.240*/241export type UnionLast<T> = UnionToIntersection<242T extends any ? () => T : never243> extends () => infer R244? R245: never246247/**248* Union to intersection.249*/250export type UnionToIntersection<U> = (251U extends any ? (k: U) => void : never252) extends (k: infer I) => void253? I254: never255256/**257* Union to tuple.258*/259export type UnionToTuple<T, L = UnionLast<T>> = [T] extends [never]260? []261: [...UnionToTuple<Exclude<T, L>>, L]262263// =============================================================================264// VALIDATION UTILITIES265// =============================================================================266267/**268* Assert type at compile time.269*/270export type AssertEqual<T, U> =271(<V>() => V extends T ? 1 : 2) extends (<V>() => V extends U ? 1 : 2)272? true273: false274275/**276* Ensure type is not never.277*/278export type IsNever<T> = [T] extends [never] ? true : false279280/**281* Ensure type is any.282*/283export type IsAny<T> = 0 extends 1 & T ? true : false284285/**286* Ensure type is unknown.287*/288export type IsUnknown<T> = IsAny<T> extends true289? false290: unknown extends T291? true292: false293294// =============================================================================295// JSON UTILITIES296// =============================================================================297298/**299* JSON-safe types.300*/301export type JsonPrimitive = string | number | boolean | null302export type JsonArray = JsonValue[]303export type JsonObject = { [key: string]: JsonValue }304export type JsonValue = JsonPrimitive | JsonArray | JsonObject305306/**307* Make type JSON-serializable.308*/309export type Jsonify<T> = T extends JsonPrimitive310? T311: T extends undefined | ((...args: any[]) => any) | symbol312? never313: T extends { toJSON(): infer R }314? R315: T extends object316? { [K in keyof T]: Jsonify<T[K]> }317: never318319// =============================================================================320// EXHAUSTIVE CHECK321// =============================================================================322323/**324* Ensure all cases are handled in switch/if.325*/326export function assertNever(value: never, message?: string): never {327throw new Error(message ?? `Unexpected value: ${value}`)328}329330/**331* Exhaustive check without throwing.332*/333export function exhaustiveCheck(_value: never): void {334// This function should never be called335}336