Skip to content

DeepPartial type ​

Makes every property optional, at every depth: a patch of a nested settings object, read-only since a patch is only read. Functions are kept whole; array items are deeply partial.

ts
import type { DeepPartial } from 'utils';

Signature ​

ts
export type DeepPartial<T> = T extends (...arguments_: readonly never[]) => unknown
  ? T
  : T extends readonly (infer Item)[]
    ? readonly DeepPartial<Item>[]
    : T extends object
      ? { readonly [K in keyof T]?: DeepPartial<T[K]> }
      : T;

Parameters ​

NameDescription
TThe type to loosen.

Example ​

ts
type SettingsPatch = DeepPartial<Settings>;
const patch: SettingsPatch = { chart: { grid: { isVisible: false } } };

Tests ​

Line coverage: 0 %.

  • ✅ makes every depth optional
  • ✅ keeps functions whole

Source ​

src/types/deep-partial.ts (on GitHub)

Used by ​

  • deepMerge: Applies a partial patch to nested settings, such as saved preferences over the defaults: plain objects are merged at every depth, other values replace, undefined keeps.
Source code
ts
/**
 * Makes every property optional, at every depth: a patch of a nested settings object, read-only since a
 * patch is only read. Functions are kept whole; array items are deeply partial.
 *
 * @template T - The type to loosen.
 * @example
 * type SettingsPatch = DeepPartial<Settings>;
 * const patch: SettingsPatch = { chart: { grid: { isVisible: false } } };
 */
export type DeepPartial<T> = T extends (...arguments_: readonly never[]) => unknown
  ? T
  : T extends readonly (infer Item)[]
    ? readonly DeepPartial<Item>[]
    : T extends object
      ? { readonly [K in keyof T]?: DeepPartial<T[K]> }
      : T;
Test file
ts
import type { DeepPartial } from './deep-partial';

interface Settings {
  readonly chart: { readonly grid: { readonly step: number }; readonly series: { readonly id: string }[] };
  format(value: number): string;
}

describe('DeepPartial', () => {
  it('makes every depth optional', () => {
    expectTypeOf<Omit<DeepPartial<Settings>, 'format'>>().toEqualTypeOf<{
      readonly chart?: {
        readonly grid?: { readonly step?: number };
        readonly series?: readonly { readonly id?: string }[];
      };
    }>();
  });

  it('keeps functions whole', () => {
    expectTypeOf<DeepPartial<Settings>['format']>().toEqualTypeOf<((value: number) => string) | undefined>();
  });
});

Keywords: deep, partial, types, type

Generated from the JSDoc of the sources.