Utility Types and Built-in Type Helpers

1. Partial<T> and Required<T> for Property Modification

Utility Type Syntax Description Use Case
Partial<T> Partial<Type> Makes all properties optional - adds ? to each property Updates, patches, partial configs
Required<T> Required<Type> Makes all properties required - removes ? from properties Validation, complete objects
Readonly<T> Readonly<Type> Makes all properties readonly - adds readonly modifier Immutable data, constants

Example: Partial<T> for optional properties

interface User {
    id: number;
    name: string;
    email: string;
    age: number;
}

// All properties optional
type PartialUser = Partial<User>;
// Result: { id?: number; name?: string; email?: string; age?: number; }

// Update function accepts partial data
function updateUser(id: number, updates: Partial<User>): User {
    const user = getUserById(id);
    return { ...user, ...updates };
}

updateUser(1, { name: "Alice" });           // OK
updateUser(2, { email: "alice@email.com" }); // OK
updateUser(3, {});                           // OK - no updates

// Partial for default configs
interface Config {
    host: string;
    port: number;
    ssl: boolean;
    timeout: number;
}

function createConfig(overrides: Partial<Config> = {}): Config {
    const defaults: Config = {
        host: "localhost",
        port: 3000,
        ssl: false,
        timeout: 5000
    };
    return { ...defaults, ...overrides };
}

Example: Required<T> to enforce completeness

interface Settings {
    theme?: "light" | "dark";
    fontSize?: number;
    notifications?: boolean;
}

// Make all required for validation
type CompleteSettings = Required<Settings>;
// Result: { theme: "light" | "dark"; fontSize: number; notifications: boolean; }

function validateSettings(settings: CompleteSettings): boolean {
    // All properties guaranteed to exist
    return settings.theme !== undefined &&
           settings.fontSize > 0 &&
           settings.notifications !== undefined;
}

// Readonly for immutable state
const config: Readonly<Config> = {
    host: "localhost",
    port: 3000,
    ssl: false,
    timeout: 5000
};

// config.port = 8080; // Error: Cannot assign to readonly property

2. Pick<T, K> and Omit<T, K> for Property Selection

Utility Type Syntax Description Use Case
Pick<T, K> Pick<Type, Keys> Select specific properties from type - creates subset DTOs, API responses, projections
Omit<T, K> Omit<Type, Keys> Remove specific properties from type - creates type without keys Exclude sensitive data, inheritance

Example: Pick<T, K> to select properties

interface User {
    id: number;
    name: string;
    email: string;
    password: string;
    role: string;
    createdAt: Date;
    updatedAt: Date;
}

// Pick only public-facing fields
type PublicUser = Pick<User, "id" | "name" | "email">;
// Result: { id: number; name: string; email: string; }

// Use for API responses
function getPublicProfile(userId: number): PublicUser {
    const user = findUser(userId);
    return {
        id: user.id,
        name: user.name,
        email: user.email
    };
}

// Pick for form fields
type LoginForm = Pick<User, "email" | "password">;
// Result: { email: string; password: string; }

// Pick with union
type UserIdentifiers = Pick<User, "id" | "email">;

// Pick for timestamps
type Timestamps = Pick<User, "createdAt" | "updatedAt">;

Example: Omit<T, K> to exclude properties

// Omit sensitive fields
type SafeUser = Omit<User, "password">;
// Result: All User fields except password

// Omit multiple fields
type UserWithoutMeta = Omit<User, "createdAt" | "updatedAt">;

// Create input type by omitting generated fields
type CreateUserInput = Omit<User, "id" | "createdAt" | "updatedAt">;
// Result: { name: string; email: string; password: string; role: string; }

function createUser(input: CreateUserInput): User {
    return {
        ...input,
        id: generateId(),
        createdAt: new Date(),
        updatedAt: new Date()
    };
}

// Omit for derived types
interface Product {
    id: string;
    name: string;
    price: number;
    discount: number;
}

type ProductInput = Omit<Product, "id">;
type ProductWithoutDiscount = Omit<Product, "discount">;

3. Record<K, T> and keyof Type Operators

Feature Syntax Description Use Case
Record<K, T> Record<Keys, Type> Create object type with specified keys and value type Dictionaries, maps, lookup tables
keyof keyof Type Union of all property keys as string/number literals Type-safe property access, mapping
typeof typeof value Extract type from value - works on values, not types Derive types from objects/functions

Example: Record<K, T> for dictionaries

// Basic Record
type UserRoles = "admin" | "user" | "guest";
type Permissions = Record<UserRoles, string[]>;

const permissions: Permissions = {
    admin: ["read", "write", "delete"],
    user: ["read", "write"],
    guest: ["read"]
};

// Record with string keys
type StringMap = Record<string, number>;
const scores: StringMap = {
    "Alice": 95,
    "Bob": 87,
    "Charlie": 92
};

// Record with template literal keys
type HTTPMethods = "GET" | "POST" | "PUT" | "DELETE";
type RouteHandlers = Record<HTTPMethods, (req: Request) => Response>;

const handlers: RouteHandlers = {
    GET: (req) => ({ status: 200, body: "GET" }),
    POST: (req) => ({ status: 201, body: "POST" }),
    PUT: (req) => ({ status: 200, body: "PUT" }),
    DELETE: (req) => ({ status: 204, body: "" })
};

// Record for configuration
type Environment = "development" | "staging" | "production";
type EnvConfig = Record<Environment, { apiUrl: string; debug: boolean }>;

const config: EnvConfig = {
    development: { apiUrl: "http://localhost:3000", debug: true },
    staging: { apiUrl: "https://staging.api.com", debug: true },
    production: { apiUrl: "https://api.com", debug: false }
};

Example: keyof for type-safe property access

interface Person {
    name: string;
    age: number;
    email: string;
}

// keyof extracts property keys
type PersonKeys = keyof Person;
// Result: "name" | "age" | "email"

// Type-safe property getter
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

const person: Person = { name: "Alice", age: 30, email: "alice@email.com" };

let name = getProperty(person, "name");     // string
let age = getProperty(person, "age");       // number
// let x = getProperty(person, "invalid");  // Error!

// Type-safe property setter
function setProperty<T, K extends keyof T>(
    obj: T,
    key: K,
    value: T[K]
): void {
    obj[key] = value;
}

setProperty(person, "name", "Bob");  // OK
setProperty(person, "age", 25);      // OK
// setProperty(person, "age", "25"); // Error: wrong type

// keyof with mapped types
type Getters<T> = {
    [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};

type PersonGetters = Getters<Person>;
// Result: { getName: () => string; getAge: () => number; getEmail: () => string; }

4. Exclude<T, U> and Extract<T, U> for Union Manipulation

Utility Type Syntax Description Result
Exclude<T, U> Exclude<Union, Excluded> Remove types from union - filters out specified types Union without excluded types
Extract<T, U> Extract<Union, Extracted> Keep only specified types from union - filters to match Union containing only extracted types
NonNullable<T> NonNullable<Type> Remove null and undefined from type Type without null/undefined

Example: Exclude<T, U> to remove types

// Basic Exclude
type AllTypes = string | number | boolean | null | undefined;
type PrimitiveTypes = Exclude<AllTypes, null | undefined>;
// Result: string | number | boolean

// Exclude specific values
type Status = "pending" | "active" | "completed" | "cancelled";
type ActiveStatus = Exclude<Status, "cancelled">;
// Result: "pending" | "active" | "completed"

// Exclude function types
type MixedTypes = string | number | (() => void) | { id: number };
type NonFunctionTypes = Exclude<MixedTypes, Function>;
// Result: string | number | { id: number }

// Exclude keys from type
type UserKeys = keyof User;
type NonIdKeys = Exclude<UserKeys, "id">;

// Practical: exclude built-in methods
type OwnProperties<T> = Exclude<keyof T, keyof any[]>;

// Remove optional properties
type RequiredKeys<T> = Exclude<{
    [K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T], undefined>;

Example: Extract<T, U> to filter types

// Basic Extract
type AllTypes = string | number | boolean | null;
type NullableTypes = Extract<AllTypes, null | undefined>;
// Result: null

type StringOrNumber = Extract<AllTypes, string | number>;
// Result: string | number

// Extract specific literal types
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
type ReadMethods = Extract<HTTPMethod, "GET">;
// Result: "GET"

type WriteMethods = Extract<HTTPMethod, "POST" | "PUT" | "DELETE" | "PATCH">;
// Result: "POST" | "PUT" | "DELETE" | "PATCH"

// Extract function types
type Mixed = string | number | ((x: number) => number) | ((y: string) => string);
type Functions = Extract<Mixed, Function>;
// Result: ((x: number) => number) | ((y: string) => string)

// Extract by structure
type Shapes = 
    | { kind: "circle"; radius: number }
    | { kind: "square"; size: number }
    | { kind: "rectangle"; width: number; height: number };

type CircleShape = Extract<Shapes, { kind: "circle" }>;
// Result: { kind: "circle"; radius: number }

// NonNullable - remove null and undefined
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// Result: string

5. ReturnType<T> and Parameters<T> for Function Types

Utility Type Syntax Description Extracts
ReturnType<T> ReturnType<Function> Extract return type from function type Function return type
Parameters<T> Parameters<Function> Extract parameter types as tuple Parameter tuple type
ConstructorParameters<T> ConstructorParameters<Class> Extract constructor parameter types Constructor params tuple
InstanceType<T> InstanceType<Constructor> Extract instance type from constructor Instance type
ThisParameterType<T> ThisParameterType<Fn> Extract this parameter type from function this type or unknown

Example: ReturnType<T> for type inference

// Basic ReturnType
function getUser() {
    return { id: 1, name: "Alice", email: "alice@email.com" };
}

type User = ReturnType<typeof getUser>;
// Result: { id: number; name: string; email: string; }

// ReturnType with generic function
function fetchData<T>(url: string): Promise<T> {
    return fetch(url).then(res => res.json());
}

type FetchReturn = ReturnType<typeof fetchData>;
// Result: Promise<unknown> (generic resolved to unknown)

// ReturnType from function type
type Handler = (event: Event) => void;
type HandlerReturn = ReturnType<Handler>;
// Result: void

// Complex function return
function getConfig() {
    return {
        api: { url: "https://api.com", timeout: 5000 },
        features: { darkMode: true, notifications: false }
    } as const;
}

type Config = ReturnType<typeof getConfig>;
// Infers readonly structure

// Array method return types
type MapReturn = ReturnType<typeof Array.prototype.map>;
type FilterReturn = ReturnType<typeof Array.prototype.filter>;

Example: Parameters<T> for parameter types

// Basic Parameters
function createUser(name: string, age: number, email: string) {
    return { name, age, email };
}

type CreateUserParams = Parameters<typeof createUser>;
// Result: [name: string, age: number, email: string]

// Use extracted parameters
function logCreateUser(...args: CreateUserParams) {
    console.log("Creating user:", args);
    return createUser(...args);
}

// Parameters with function type
type HandlerFn = (event: MouseEvent, options: { passive: boolean }) => void;
type HandlerParams = Parameters<HandlerFn>;
// Result: [event: MouseEvent, options: { passive: boolean }]

// Extract specific parameter
type FirstParam<T extends (...args: any[]) => any> = Parameters<T>[0];

type Handler = (id: number, data: string) => void;
type FirstArg = FirstParam<Handler>;  // number

// Combine with ReturnType
function transform(input: string): number {
    return parseInt(input);
}

type TransformParams = Parameters<typeof transform>;  // [string]
type TransformReturn = ReturnType<typeof transform>;  // number

6. NonNullable<T> and InstanceType<T> Helpers

Utility Type Syntax Description Use Case
NonNullable<T> NonNullable<Type> Remove null and undefined from type Validation, type narrowing
InstanceType<T> InstanceType<Constructor> Get instance type from constructor function Factory patterns, DI containers
Awaited<T> TS 4.5+ Awaited<Promise> Recursively unwrap Promise types Async function return types

Example: NonNullable<T> for type safety

// Basic NonNullable
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// Result: string

// NonNullable with union
type Value = string | number | null | undefined | boolean;
type NonNullValue = NonNullable<Value>;
// Result: string | number | boolean

// Filter array to non-null values
function filterNulls<T>(arr: (T | null | undefined)[]): NonNullable<T>[] {
    return arr.filter((item): item is NonNullable<T> => item != null);
}

const mixed = [1, null, 2, undefined, 3];
const numbers = filterNulls(mixed);  // number[]

// Safe access with NonNullable
type User = { name: string; email?: string | null };

function getEmail(user: User): NonNullable<User["email"]> | "no-email" {
    return user.email ?? "no-email";
}

// NonNullable in generic constraints
function process<T>(value: NonNullable<T>): void {
    // value is guaranteed not null/undefined
    console.log(value);
}

Example: InstanceType<T> for constructor types

// Basic InstanceType
class User {
    constructor(public name: string, public age: number) {}
}

type UserInstance = InstanceType<typeof User>;
// Result: User

// Factory function with InstanceType
function createInstance<T extends new (...args: any[]) => any>(
    constructor: T,
    ...args: ConstructorParameters<T>
): InstanceType<T> {
    return new constructor(...args);
}

const user = createInstance(User, "Alice", 30);  // User

// InstanceType with abstract classes
abstract class Animal {
    abstract makeSound(): void;
}

class Dog extends Animal {
    makeSound() { console.log("Woof!"); }
}

type DogInstance = InstanceType<typeof Dog>;  // Dog

// Registry pattern
class Registry {
    private constructors = new Map<string, new (...args: any[]) => any>();
    
    register<T extends new (...args: any[]) => any>(
        name: string,
        constructor: T
    ): void {
        this.constructors.set(name, constructor);
    }
    
    create<T extends new (...args: any[]) => any>(
        name: string,
        ...args: any[]
    ): InstanceType<T> | undefined {
        const Constructor = this.constructors.get(name) as T;
        return Constructor ? new Constructor(...args) : undefined;
    }
}

Example: Awaited<T> for Promise unwrapping

// Awaited unwraps Promise types
type StringPromise = Promise<string>;
type UnwrappedString = Awaited<StringPromise>;
// Result: string

// Deep unwrapping
type NestedPromise = Promise<Promise<number>>;
type UnwrappedNumber = Awaited<NestedPromise>;
// Result: number

// Awaited with async function
async function fetchUser(): Promise<{ id: number; name: string }> {
    return { id: 1, name: "Alice" };
}

type FetchedUser = Awaited<ReturnType<typeof fetchUser>>;
// Result: { id: number; name: string }

// Non-Promise types pass through
type NotPromise = Awaited<string>;
// Result: string

// Awaited with union
type MixedPromises = Promise<string> | Promise<number> | boolean;
type UnwrappedMixed = Awaited<MixedPromises>;
// Result: string | number | boolean

Utility Types Reference

Property Modifiers

  • Partial<T> - Optional
  • Required<T> - Required
  • Readonly<T> - Immutable

Property Selection

  • Pick<T, K> - Include
  • Omit<T, K> - Exclude
  • Record<K, T> - Create

Union Manipulation

  • Exclude<T, U> - Remove
  • Extract<T, U> - Filter
  • NonNullable<T> - Clean

Function Types

  • ReturnType<T> - Return type
  • Parameters<T> - Param tuple
  • ConstructorParameters<T> - Constructor args

Class Types

  • InstanceType<T> - Instance
  • ThisParameterType<T> - this type
  • Awaited<T> - Unwrap Promise