# TypeScript Utility Types Reference ## Table of Contents 1. [Built-in Utility Types](#built-in-utility-types) 2. [Custom Utility Types](#custom-utility-types) 3. [Type-Safe Object Operations](#type-safe-object-operations) 4. [Array/Tuple Utilities](#arraytuple-utilities) 5. [Function Utilities](#function-utilities) --- ## Built-in Utility Types ### Object Shape Utilities ```typescript // Partial - Make all properties optional interface User { id: string; name: string; email: string; } type UpdateUser = Partial; // { id?: string; name?: string; email?: string } function updateUser(id: string, patch: Partial): User { /* ... */ } // Required - Make all properties required interface Config { host?: string; port?: number; debug?: boolean; } type StrictConfig = Required; // { host: string; port: number; debug: boolean } // Readonly - Make all properties readonly type ImmutableUser = Readonly; // { readonly id: string; readonly name: string; ... } const frozen: ImmutableUser = { id: '1', name: 'Alice', email: 'a@b.com' }; // frozen.name = 'Bob'; // Error: cannot assign to 'name' because it is a read-only property // Record - Create an object type with keys K and values T type UserMap = Record; type StatusMap = Record<'active' | 'inactive' | 'banned', number>; type HttpStatus = Record<200 | 404 | 500, string>; // Pick - Select a subset of properties type UserPreview = Pick; // { id: string; name: string } type Credentials = Pick; // { email: string } // Omit - Exclude specific properties type PublicUser = Omit; // { id: string; name: string } type NewUser = Omit; // { name: string; email: string } ``` ### Union Manipulation Utilities ```typescript // Exclude - Remove U from union T type NonBoolean = Exclude; // string | number type NonNullish = Exclude; // string type NonString = Exclude; // number | boolean // Extract - Keep only members of T that are assignable to U type OnlyStrings = Extract; // string type Primitives = Extract; // string | number // NonNullable - Remove null and undefined from T type SafeString = NonNullable; // string type SafeUser = NonNullable; // User ``` ### Function Utilities ```typescript function fetchData(url: string, timeout: number, headers: Record): Promise { return fetch(url); } // ReturnType - Get the return type of a function type type FetchResult = ReturnType; // Promise type StringLength = ReturnType; // number // Parameters - Get parameters as a tuple type type FetchParams = Parameters; // [url: string, timeout: number, headers: Record] // Call a function with stored parameters function withDefaults unknown>( fn: T, defaults: Partial> ) { /* ... */ } // ConstructorParameters - Get constructor parameter types class HttpClient { constructor(baseUrl: string, timeout: number) {} } type HttpArgs = ConstructorParameters; // [string, number] // InstanceType - Get the type of a class instance type ClientInstance = InstanceType; // HttpClient // ThisParameterType - Extract the type of 'this' function greet(this: { name: string }, greeting: string): string { return `${greeting}, ${this.name}`; } type GreetThis = ThisParameterType; // { name: string } // OmitThisParameter - Remove this parameter from function type type GreetFn = OmitThisParameter; // (greeting: string) => string ``` ### Awaited and String Utilities ```typescript // Awaited - Recursively unwrap Promise type A = Awaited>; // string type B = Awaited>>; // number type C = Awaited>; // string | number async function loadData(): Promise { return []; } type LoadResult = Awaited>; // User[] // String manipulation (compile-time only, no runtime effect) type UpperName = Uppercase<'hello'>; // 'HELLO' type LowerName = Lowercase<'WORLD'>; // 'world' type CapName = Capitalize<'alice'>; // 'Alice' type UnCapName = Uncapitalize<'Hello'>; // 'hello' // Useful for generating method names type Methods = `get${Capitalize}` | `set${Capitalize}`; type NameMethods = Methods<'name' | 'age'>; // 'getName' | 'getAge' | 'setName' | 'setAge' ``` --- ## Custom Utility Types ### DeepReadonly ```typescript type DeepReadonly = T extends (infer U)[] ? ReadonlyArray> : T extends object ? { readonly [K in keyof T]: DeepReadonly } : T; interface AppState { user: { id: string; profile: { name: string; bio: string } }; settings: { theme: string; notifications: boolean[] }; } type FrozenState = DeepReadonly; declare const state: FrozenState; // state.user.profile.name = 'x'; // Error - deeply readonly ``` ### DeepPartial ```typescript type DeepPartial = T extends (infer U)[] ? DeepPartial[] : T extends object ? { [K in keyof T]?: DeepPartial } : T; // Useful for deep merge / patch operations function deepMerge(target: T, patch: DeepPartial): T { if (typeof patch !== 'object' || patch === null) return patch as T; const result = { ...target }; for (const key of Object.keys(patch) as (keyof T)[]) { const val = patch[key as keyof typeof patch]; if (val !== undefined) { (result[key] as unknown) = typeof val === 'object' && val !== null ? deepMerge(result[key] as object, val as DeepPartial) : val; } } return result; } ``` ### Nullable and Optional ```typescript type Nullable = T | null; type Optional = T | undefined; type NullableOptional = T | null | undefined; // Require at least one of specified keys type RequireAtLeastOne = Omit & { [K in Keys]-?: Required> & Partial> }[Keys]; // Require exactly one of specified keys type RequireExactlyOne = Omit & { [K in Keys]: Required> & { [O in Exclude]?: never } }[Keys]; ``` ### Merge and UnionToIntersection ```typescript // Merge two types, second overrides first type Merge = Omit & U; type A = { id: string; name: string; active: boolean }; type B = { name: number; extra: string }; // name changes type type C = Merge; // { id: string; active: boolean; name: number; extra: string } // Convert a union to an intersection type UnionToIntersection = (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never; type IntersectedABC = UnionToIntersection<{ a: string } | { b: number } | { c: boolean }>; // { a: string } & { b: number } & { c: boolean } // Prettify - flatten intersection types for readable IDE output type Prettify = { [K in keyof T]: T[K] } & {}; ``` ### Exact and StrictOmit ```typescript // Ensure no extra properties (useful in function params) type Exact = T extends Shape ? Exclude extends never ? T : never : never; // StrictOmit: errors if K is not in T (unlike Omit which silently ignores) type StrictOmit = Omit; ``` --- ## Type-Safe Object Operations ### Type-Safe pick ```typescript function pick(obj: T, keys: K[]): Pick { return keys.reduce((acc, key) => { acc[key] = obj[key]; return acc; }, {} as Pick); } const user: User = { id: '1', name: 'Alice', email: 'a@b.com' }; const preview = pick(user, ['id', 'name']); // { id: string; name: string } // TypeScript knows preview has only 'id' and 'name' ``` ### Type-Safe omit ```typescript function omit(obj: T, keys: K[]): Omit { const result = { ...obj }; keys.forEach((key) => delete result[key]); return result as Omit; } const publicUser = omit(user, ['email']); // { id: string; name: string } ``` ### Type-Safe merge ```typescript function merge(base: T, override: U): Merge { return { ...base, ...override } as Merge; } type Merge = Omit & U; ``` ### Type-Safe diff (keys present in T but not U) ```typescript type Diff = Pick>; type OnlyInA = Diff<{ a: string; b: number; c: boolean }, { b: number; d: string }>; // { a: string; c: boolean } ``` --- ## Array/Tuple Utilities ### Head, Tail, Last, Reverse ```typescript // First element of a tuple type Head = T extends [infer H, ...unknown[]] ? H : never; // All but first element type Tail = T extends [unknown, ...infer R] ? R : never; // Last element of a tuple type Last = T extends [...unknown[], infer L] ? L : never; // Reverse a tuple type Reverse = T extends [infer Head, ...infer Rest] ? Reverse : Acc; type H = Head<[string, number, boolean]>; // string type T = Tail<[string, number, boolean]>; // [number, boolean] type L = Last<[string, number, boolean]>; // boolean type R = Reverse<[1, 2, 3]>; // [3, 2, 1] ``` ### Flatten Types ```typescript // Flatten one level type Flatten = T extends (infer U)[] ? U : T; type F = Flatten; // string[] // Flatten nested arrays recursively type DeepFlatten = T extends (infer U)[] ? U extends unknown[] ? DeepFlatten : U : T; type Deep = DeepFlatten; // string ``` ### Zip Two Tuples ```typescript type Zip = T extends [infer TH, ...infer TR] ? U extends [infer UH, ...infer UR] ? [[TH, UH], ...Zip] : [] : []; type Zipped = Zip<[1, 2, 3], ['a', 'b', 'c']>; // [[1, 'a'], [2, 'b'], [3, 'c']] ``` ### Length and Indices ```typescript type Length = T['length']; // Generate numeric union of indices type Indices = Exclude; type Len = Length<[1, 2, 3]>; // 3 type Idx = Indices<['a', 'b', 'c']>; // '0' | '1' | '2' ``` --- ## Function Utilities ### Promisify Type ```typescript // Convert a callback-style function type to one returning a Promise type Promisify unknown> = T extends (...args: infer A) => infer R ? R extends Promise ? T : (...args: A) => Promise> : never; type SyncFn = (x: number) => string; type AsyncFn = Promisify; // (x: number) => Promise ``` ### Curry Type ```typescript type Head = T extends [infer H, ...unknown[]] ? H : never; type Tail = T extends [unknown, ...infer R] ? R : never; type Curried = TArgs extends [] ? TReturn : (arg: Head) => Curried, TReturn>; declare function curry( fn: (...args: TArgs) => TReturn ): Curried; const add = curry((a: number, b: number) => a + b); const inc = add(1); // Curried<[number], number> = (b: number) => number const two = inc(1); // number ``` ### Overload Helper ```typescript // Extract all overload signatures as a union type Overloads unknown> = T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; (...args: infer A4): infer R4; } ? ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) | ((...args: A4) => R4) : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2; (...args: infer A3): infer R3; } ? ((...args: A1) => R1) | ((...args: A2) => R2) | ((...args: A3) => R3) : T extends { (...args: infer A1): infer R1; (...args: infer A2): infer R2 } ? ((...args: A1) => R1) | ((...args: A2) => R2) : T; ``` ### Memoize with Type Safety ```typescript type AnyFn = (...args: unknown[]) => unknown; function memoize(fn: T): T { const cache = new Map>(); return ((...args: Parameters): ReturnType => { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key) as ReturnType; const result = fn(...args) as ReturnType; cache.set(key, result); return result; }) as T; } const expensiveCalc = memoize((a: number, b: number): number => a * b); expensiveCalc(2, 3); // 6 - computed expensiveCalc(2, 3); // 6 - cached ```