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