zod
zod copied to clipboard
Inferred type of Object catchall with boolean is empty object
const schema = z.object({}).catchall(z.boolean());
type T = z.output<typeof schema>;
// ^? {}
I am expecting type T = Record<string, boolean>, but inferred type is empty object instead.
Are you only wanting to report the bug? or are you looking for a temp workaround?
Was just reporting a bug.
I am currently using this workaround:
z.object({}).catchall(z.boolean()) as z.ZodObject<
z.ZodRawShape,
'strip',
z.ZodBoolean,
Record<string, boolean>
>
This is intentional. Unfortunately the runtime behavior of .catchall() does not agree with TypeScript's interpretation of index signatures. For instance you can't declare this type:
type A = {
name: string;
[k:string]: number
};
The [k: string] (or the Record<> type you proposed) applies to all elements of the object type, including named properties. It isn't a "catchall" in the way Zod treats it. This is why .catchall() doesn't change the inferred type. There's no syntax in TypeScript to represent a "catchall index signature".
@valeneiko Consider z.record for your specific use case.
@colinhacks wouldn't intersecting an index signature with an object capture the semantics of .catchall()?
type X = {
x: number
} & {
[key: string]: boolean
};
type Q1 = X['x'];
// ^? type Q1 = number
type Q2 = X['y'];
// ^? type Q2 = boolean
Nvm, just realized the type is not actually usable, just displays like that.
Nvm, just realized the type is not actually usable, just displays like that.
Indeed, this is exactly what threw me off in the first place 😅
Apologies, this actually is a bug. See my reply here: https://github.com/colinhacks/zod/pull/3282
Fixed in Zod 3.23