MediumGenerics📖 Theory Question

What is the Partial, Required, and Readonly pattern when building generic utility functions?

💡

Hint

Combine utility types in function signatures to produce modified shapes — common in config and builder patterns

Full Answer

Generic utility functions compose TypeScript's built-in modifiers to create flexible, type-safe APIs.

// Deep partial — makes all nested properties optional
type DeepPartial<T> = T extends object
  ? { [K in keyof T]?: DeepPartial<T[K]> }
  : T;

function mergeDefaults<T extends object>(
  defaults: T,
  overrides: DeepPartial<T>
): T {
  return { ...defaults, ...overrides } as T;
}

const config = mergeDefaults(
  { host: 'localhost', port: 3000, ssl: false },
  { port: 8080 } // only override port — others keep defaults
);
// Update function — require at least one field
type AtLeastOne<T> = { [K in keyof T]-?: Pick<T, K> & Partial<T> }[keyof T];

function update<T extends object>(id: number, patch: Partial<T>): void {
  // ...apply patch
}

// Freeze function — returns readonly version
function freeze<T extends object>(obj: T): Readonly<T> {
  return Object.freeze(obj);
}

const settings = freeze({ theme: 'dark', lang: 'en' });
settings.theme = 'light'; // ❌ Error — readonly
💡 The pattern Partial<T> for update functions and Required<T> for build/create functions is idiomatic TypeScript. It prevents passing full objects when you only need to patch a few fields.

More Generics Questions

EasyWhat are generics and why are they useful in TypeScript?→EasyWhat are generic constraints and how do you use the extends keyword with them?→EasyWhat are default type parameters in TypeScript generics?→EasyWhat is conditional generic typing — how do you write T extends U ? X : Y?→

Practice this in a timed sprint →

5 free questions, no signup required

⚡ Start Sprint