I'm working on a Zod schema for nodes where each node got a unique ID, unique type and an array of child nodes. Because of that I created a helper function acting as a base schema for nodes
function createNodeSchema<const NodeType extends string>(nodeType: NodeType) {
return z.object({
// ... base fields for nodes ...
id: z.string(),
type: z.literal(nodeType),
// due to circular imports we can't use the discriminated union directly and have to type it manually
get children(): z.ZodArray<
z.ZodDiscriminatedUnion<[typeof childBarNodeSchema]>
> {
return z.array(z.discriminatedUnion('type', [childBarNodeSchema]));
},
});
}
Assuming there is a root node schema
const leadingFooNodeSchema = createNodeSchema('leadingFoo').extend({
// ...fields for this node ...
foo: z.string(),
});
and a child node schema
const childBarNodeSchema = createNodeSchema('followingBar').extend({
// ...fields for this node ...
bar: z.string(),
});
the whole tree will be bundled into a root schema
const rootNodeBaseSchema = z.discriminatedUnion('type', [
leadingFooNodeSchema,
// ...other leading nodes...
]);
const rootNodeSchema = rootNodeBaseSchema.refine(haveNodesUniqueIDs, {
error: 'Nodes must have unique IDs',
});
The validation function haveNodesUniqueIDs checks if there are duplicate IDs in the tree
// I am really not sure about that one...
type RecursivePick<T, K extends keyof T> = {
[P in Extract<keyof T, K>]: P extends 'children'
? T[P] extends Array<infer U>
? RecursivePick<U, Extract<keyof U, K>>[]
: never
: T[P];
};
// try to extract only "id" and "children" from the whole tree because we don't care for other fields
type NodeSchemaWithIDAndChildren = RecursivePick<
z.infer<typeof rootNodeSchema>,
'id' | 'children'
>;
function haveNodesUniqueIDs(leadingNode: NodeSchemaWithIDAndChildren) {
// ... implementation goes here...
}
Everything is looking good so far. But when it comes to testing
describe('haveNodesUniqueIDs', () => {
it('returns true ...', () => {
expect(
haveNodesUniqueIDs({
id: 'a',
children: [],
})
).toBeTruthy();
});
});
the testrunner fails with the following error
ReferenceError: Cannot access 'vite_ssr_import_1' before initialization
It's pointing at the createNodeSchema => children so maybe my schema is not correct yet.
I created a playground for that => https://stackblitz.com/edit/vitejs-vite-ue55oieh?file=test%2FhaveNodesUniqueIDs.test.ts&view=editor
Do you have any ideas how to fix this?
childBarNodeSchema, butchildBarNodeSchemaitself is created by callingcreateNodeSchema. This circular reference means when the module loads, the code tries to usechildBarNodeSchemabefore it's fully initialised, causing theReferenceError