Skip to content

Is object a footgun?Β #1325

@valadaptive

Description

@valadaptive

The documentation for the object() schema states:

The object schema removes unknown entries. This means that entries that you have not defined in the first argument are not validated and added to the output. You can change this behavior by using the looseObject or strictObject schema instead.

This can lead to some surprising behavior when all the object's properties are optional. An object schema with all-optional properties will successfully parse any value that is an object, and convert it into an empty object.

The first way this manifests is around arrays. An object schema with all-optional properties will successfully parse an array into an empty object:

const Schema = v.object({
  foo: v.optional(v.string())
});

const result = v.parse(Schema, [1, 2, 3, 4, 5]);

console.log(result);
[log]: {}

If we try this with looseObject, it converts the array into a plain object with numeric properties (this is also surprising!):

[log]: {
  0: 1,
  1: 2,
  2: 3,
  3: 4,
  4: 5
}

And strictObject fails as expected.

The second surprising case is around unions, and was brought up in #1317. If an object schema with all-optional properties is put into a union, it'll always succeed, and may strip properties present in other union branches:

let D = v.union([v.object({ a1: v.optional(v.string()) }), v.object({ a2: v.optional(v.string()) })]);

console.log(v.parse(D, { a2: '222' }));
[log]: {}

In this case, both looseObject and strictObject will return the correct result: looseObject will not strip a2, and strictObject will make the first union branch fail to parse and move on to the second.

For a future version of Valibot, I think the following API would result in the fewest footguns:

  • Remove object entirely. Silently stripping unknown properties just does too many weird things.
  • Change looseObject so it does not re-create the object. This would make it truly structurally typed, and avoid the surprising array behavior mentioned above.
  • Keep strictObject as-is.

I should also mention that it was very surprising to discover that Valibot re-creates every object it parses! All its documentation heavily refers to it as a "validation" library, and I don't expect data to change shape when it is "validated".

Metadata

Metadata

Assignees

Labels

documentationImprovements or additions to documentationfeedbackGeneral feedback that does not result in changes

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions