Skip to content

Instantly share code, notes, and snippets.

@navix
Last active August 4, 2023 09:02
Show Gist options
  • Star 36 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • 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]>
};

@zallek
Copy link

zallek commented Dec 11, 2018

Thanks

@inad9300
Copy link

This solution is not complete, so be careful. You need to account for arrays, and possibly other cases. See https://stackoverflow.com/questions/45372227/how-to-implement-typescript-deep-partial-mapped-type-not-breaking-array-properti/49936686#49936686.

@navix
Copy link
Author

navix commented Dec 25, 2018

@inad9300 thanks!

@insidewhy
Copy link

@navix Your solution there is great for typescript 3.0, unfortunately the use of infer breaks the ability to get code completion when using DeepPartial in argument position (you get type verification only). So for typescript 3.1 and later, the following is much better:

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

@navix
Copy link
Author

navix commented Apr 18, 2020

@insidewhy you're right!

Thanks for the update. 😎

@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