TypeScript: deep partial?
Is there a way to specify a partial type in TypeScript that also makes all child objects partials as well? For example:
interface Foobar {
foo: number;
bar: {
baz: boolean;
qux: string;
};
}
const foobar: Partial<Foobar> = {
foo: 1,
bar: { baz: true }
};
This throws the following error:
TS2741: Property 'qux' is missing in type '{ baz: true; }' but required in type '{ baz: boolean; qux: string; }'.
Is there any way to make child nodes partials as well?
Solution 1:
You can simply create a new type, say, DeepPartial
, which basically references itself (updated Jan 2022 to handle possible non-objects):
type DeepPartial<T> = T extends object ? {
[P in keyof T]?: DeepPartial<T[P]>;
} : T;
Then, you can use it as such:
const foobar: DeepPartial<Foobar> = {
foo: 1,
bar: { baz: true }
};
See proof-of-concept example on TypeScript Playground.
Solution 2:
If you're looking for a quick and easy solution, check out the type-fest package, which has many useful prebuilt TypeScript types including the PartialDeep
type.
For a more technical and customizable solution, see this answer.
Solution 3:
I inspired myself on the answers on this question to create my own version of PartialDeep.
I stumbled upon some issues with built-in objects along the way; for my use case, I wouldn't expect a Date
object to be missing some of its methods.
It's either there, or it isn't.
Here's my version:
// Primitive types (+ Date) are themselves. Or maybe undefined.
type PartialDeep<T> = T extends string | number | bigint | boolean | null | undefined | symbol | Date
? T | undefined
// Arrays, Sets and Maps and their readonly counterparts have their items made
// deeply partial, but their own instances are left untouched
: T extends Array<infer ArrayType>
? Array<PartialDeep<ArrayType>>
: T extends ReadonlyArray<infer ArrayType>
? ReadonlyArray<ArrayType>
: T extends Set<infer SetType>
? Set<PartialDeep<SetType>>
: T extends ReadonlySet<infer SetType>
? ReadonlySet<SetType>
: T extends Map<infer KeyType, infer ValueType>
? Map<PartialDeep<KeyType>, PartialDeep<ValueType>>
: T extends ReadonlyMap<infer KeyType, infer ValueType>
? ReadonlyMap<PartialDeep<KeyType>, PartialDeep<ValueType>>
// ...and finally, all other objects.
: {
[K in keyof T]?: PartialDeep<T[K]>;
};