Inferred typescript types do not match parsing behavior => unexpected behavior with intersect #1366
-
|
I'll start with a simple example: const SimpleSchema = V.object({ x: V.number() });
type TSimpleInput = V.InferInput<typeof SimpleSchema>; // { x: number; } but in practice { x: number; [key: string]: any; }
type TSimpleOutput = V.InferOutput<typeof SimpleSchema>; // { x: number; }
console.debug(
"simple object parse result:",
V.safeParse(SimpleSchema, { x: 5, y: 7 })
);So the inferred input type is stricter than what safeParse will allow. This bug (in my opinion) is also reflected in the intersection docs: https://valibot.dev/guides/intersections/, which further suggests that the implementation is not in line with people's intuition about how it should work: These docs use the following example: // TypeScript
type Intersect = { foo: string } & { bar: number };
// Valibot
const IntersectSchema = v.intersect([
v.object({ foo: v.string() }),
v.object({ bar: v.number() }),
]);but in reality we get: // TypeScript
type Intersect = { foo: string; [key: string]: any; } & { bar: number; [key: string]: any; };
// Valibot
const IntersectSchema = v.intersect([
v.object({ foo: v.string() }),
v.object({ bar: v.number(); }),
]);because when parsing, it will not complain about extra properties, whereas the typescript compiler would complain about extra properties in the first version. This gets worse when using a strictObject: const firstSchema = v.strictObject({
a: v.number(),
b: v.string(),
});
type TFirstInput = v.InferInput<typeof firstSchema>; // { a: number; b: string }
const secondSchema = v.strictObject({
c: v.number(),
});
type TSecondInput = v.InferInput<typeof secondSchema>; // { c: number; }
const intersectSchema = v.intersect([firstSchema, secondSchema]);
type TIntersectInput = v.InferInput<typeof intersectSchema>; // { a: number; b: string; c: number; }
console.debug(
"intersectSchema parse result:",
v.safeParse(intersectSchema, { a: 1, b: "foo", c: 3 })
); // => {
// typed: false,
// success: false,
// output: { a: 1, b: "foo", c: 3 },
// issues: [
// 'Invalid key: Expected never but received "c"',
// 'Invalid key: Expected never but received "a"',
// ] This is not inline with the inferred types, but also unintuitive (as well as useless) from a user perspective. (Unfortunately zod has the exact same bug) REMARK: if this is how it is supposed to work, then I let Github Copilot crunch on the issue to make it behave the way I would expect it to behave: https://github.com/mrft/valibot/tree/feat-intersect-strict |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
|
@fabian-hiller |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for your response. I am happy that zod fixed the bug recently: colinhacks/zod#5491 I would argue that it should be the intent of "zod-like" libraries that parsing behavior should stay as close as possible to typescript's behavior. Disclaimer: I stumbled upon valibot when searching for an alternative to zod because it used to have the same bug, so excuse me if the way I formulate things is not 'the valibot way'. Now, in my case I am building calculation modules. Imagine something like In some cases I need to do some extra validation checks, for example if 'screws' is an array of multiple screw sizes, and 'screwdrivers' is another array, I should check that all the needed screw drivers are available (this is just a theoretical example, but you get the point). So this is a 'refined' schema. Some calculations (or at least their input schema) can be reused in multiple modules, so I want to be able to create a new strict schema that combines schema1WithChecks (screws & screwdrivers) with schema2WithChecks (hammers & nails). And obviously I want proper autocompletion in the IDE. The problem with valibot right now is that although the types seem to suggest that combining these can be done easily (cfr. inferred schema I hope this clarifies things a little bit. |
Beta Was this translation helpful? Give feedback.
Thank you! I created an issue: #1389