Skip to content

Instantly share code, notes, and snippets.

@navix
Last active August 4, 2023 09:02
Show Gist options
  • Save navix/6c25c15e0a2d3cd0e5bce999e0086fc9 to your computer and use it in GitHub Desktop.
Save navix/6c25c15e0a2d3cd0e5bce999e0086fc9 to your computer and use it in GitHub Desktop.
TypeScript Deep Partial Interface

TypeScript Deep Partial Interface

export type DeepPartial<T> = T extends Function ? T : (T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T);

Before typescript@3.1

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends Array<infer U>
    ? Array<DeepPartial<U>>
    : T[P] extends ReadonlyArray<infer U>
      ? ReadonlyArray<DeepPartial<U>>
      : DeepPartial<T[P]>
};

@tguichaoua
Copy link

Function type are convert into {}.
Here a correction:

export type DeepPartial<T> = T extends Function ? T : (T extends object ? { [P in keyof T]?: DeepPartial<T[P]>; } : T);

@navix
Copy link
Author

navix commented Apr 26, 2020

@baanloh Thanks, updated! 🐱‍💻

@richard-ejem
Copy link

Array elements are made optional too, which is quite disputable.
Example:

type Shape = {
  color: string;
  points: {x: number; y: number}[];
}

I'd expect this result from DeepPartial<Shape> :

{
  color?: string;
  points?: {x?: number; y?: number}[];
}

However it currently resolves this way:

{
  color?: string;
  points?: ({x?: number; y?: number} | undefined)[];
}

It is disputable since Partial<string[]> resolves to (string | undefined)[], but this is intuitive when I apply Partial directly on an array. But if I apply DeepPartial to express some large partial structure, I would not expect undefined in array elements.

It can be fixed this way:

export type DeepPartial<T> = T extends Function
  ? T
  : (T extends object
    ? T extends unknown[]
      ? DeepPartial<T[number]>[]
      : { [P in keyof T]?: DeepPartial<T[P]>; }
    : T
  );

@aitchkhan
Copy link

aitchkhan commented Jul 2, 2021

For typeorm:

import { QueryDeepPartialEntity } from 'typeorm/query-builder/QueryPartialEntity';

and be used like:

QueryDeepPartialEntity<User[]>

this does the same trick.

@mauriciabad
Copy link

I did this workaround to keep promises:

export type DeepPartial<T> = 
    T extends Promise<infer Y>        ? Promise<DeepPartial<Y>>
  : T extends (...args: any[]) => any ? T
  : T extends object                  ? { [P in keyof T]?: DeepPartial<T[P]> }
  : T

@chuasonglin1995
Copy link

For me, I need that Partial<T[K]> instead of T

export type DeepPartial<T> = {
  [K in keyof T]?: T[K] extends Record<string, unknown> ? DeepPartial<T[K]> : Partial<T[K]>
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment