Created
June 14, 2023 13:06
-
-
Save lauslim12/61467480b34cac5d3763dc1ec198d9ef to your computer and use it in GitHub Desktop.
Experiments to deeply merge nested objects in Zod library.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// mkdir zod-deep-merge-experiement | |
// Copy and paste this code to your editor, save as `index.ts` | |
// yarn init --yes | |
// yarn add ts-node zod typescript @types/node | |
// yarn run tsc --init | |
// yarn run ts-node . | |
import { strict as assert } from "node:assert"; | |
import { z } from "zod"; | |
/** | |
* All schemas | |
*/ | |
const personSchema = z.object({ | |
name: z.string(), | |
hobbies: z.array(z.string()), | |
attributes: z.record(z.string()), | |
company: z.object({ | |
name: z.string(), | |
address: z.string(), | |
train: z.enum(["Yamanote", "Fukutoshin", "Tobu-Tojo", "Seibu Shinjuku"]), | |
}), | |
}); | |
const alternativePersonSchema = z.object({ | |
address: z.string(), | |
age: z.number(), | |
description: z.string(), | |
company: z.object({ | |
profession: z.string(), | |
description: z.string(), | |
}), | |
}); | |
/** | |
* First solution, dirty solution. | |
*/ | |
const coalescedPerson = z | |
.object({}) | |
.merge(personSchema) | |
.merge(alternativePersonSchema) | |
.deepPartial() | |
.and(personSchema.pick({ company: true }).deepPartial()); | |
type CoalescedPerson = z.infer<typeof coalescedPerson>; | |
/** | |
* Second solution, a bit clearer because there's no `pick` and `deepPartial` in one line. We just | |
* create a new schema based on what is required to be deeply merged, so we can reuse this in the next step. | |
*/ | |
const nestedCompany = z.object({ | |
company: z | |
.object({}) | |
.merge(personSchema.shape.company) | |
.merge(alternativePersonSchema.shape.company), | |
}); | |
const alternativeCoalescedPerson = z | |
.object({}) | |
.merge(personSchema) | |
.merge(alternativePersonSchema) | |
.merge(nestedCompany) | |
.deepPartial(); | |
type AlternativeCoalescedPerson = z.infer<typeof alternativeCoalescedPerson>; | |
if (require.main === module) { | |
const T: CoalescedPerson = { company: { profession: "Building Management" } }; | |
const K: AlternativeCoalescedPerson = { company: { train: "Yamanote" } }; | |
assert.deepStrictEqual(T, { company: { profession: "Building Management" } }); | |
assert.deepStrictEqual(K, { company: { train: "Yamanote" } }); | |
console.log(T, K); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment