valibot icon indicating copy to clipboard operation
valibot copied to clipboard

Pipe not applying on tuple with only the items parameter

Open gcornut opened this issue 2 years ago • 7 comments

Hi, I think I found a bug on the tuple schema.

If I create a schema tuple([number()], string(), [maxLength(1)]) (items, rest & pipe) and try to parse against [1, 'a'], as expected, I get an Invalid length error.

But if I create a schema tuple([number()], [maxLength(1)]) (items & pipe) and try to parse against [1, 2], I don't get any error.

gcornut avatar Oct 31 '23 22:10 gcornut

This is expected since v0.20.0. 🤓 If no rest argument is given, tuple ignores all potential rest items. This means that they will not be in the output and the tuple is therefore valid. Also, maxLength makes no sense for a tuple without a rest argument, since it has a fixed length.

The current implementation allows the developer to decide whether to simply ignore potential rest elements (the default) or to deliberately prevent them by using never() for the rest argument. So tuple has the same behavior as object. However, I understand that there will be different opinions on this, and I am interested in hearing them.

fabian-hiller avatar Nov 01 '23 00:11 fabian-hiller

Ok I see the logic here. And I think I will prefer using tuple([number()], never()) rather than tuple([number()], [maxLength(1)]).

However, it's still a bit weird that length constraint are forced inside the tuple implementation when no rest parameter is provided. If I understand correctly tuple([number()]) is equivalent to tuple([number()], any()), right ? If so, then isn't it weird that tuple([number()], [maxLength(1)]) is not equivalent to tuple([number()], any(), [maxLength(1)]) ?

gcornut avatar Nov 02 '23 08:11 gcornut

Yes, as I said, tuple behaves in the same way as object and removes everything that is not defined by default. Basically, it removes what you are not interested in either way. Via the rest argument you can change this behaviour. With tuple([number()], never()) you can make your tuple strict and with tuple([number()], string()) you can allow any other data type, in the example strings, as the tuple rest.

The alternative to this would be to make it strict by default and throw an error if the length of the input does not match the tuple length. However, this would have the consequence that this behavior could not or only hardly be changed afterwards.

tuple([number()]) is not the same as tuple([number()], any()). The type signature is different and so also the output.

Even if I leave it as it is for now, I am very interested in further feedback and ideas. But we should find a final solution by v1.

fabian-hiller avatar Nov 02 '23 18:11 fabian-hiller

Ah ok I see now, thanks !

gcornut avatar Nov 02 '23 20:11 gcornut

Please let me know if you have any ideas how to improve this or any other issue. I plan to publish v1 in January.

fabian-hiller avatar Nov 02 '23 21:11 fabian-hiller

I don't have a better idea no. But a good documentation of tuple would certainly help :)

gcornut avatar Nov 03 '23 15:11 gcornut

I agree! Thanks for pointing that out!

fabian-hiller avatar Nov 03 '23 15:11 fabian-hiller

I will close this issue as our pipeline implementation has completely changed.

fabian-hiller avatar Jun 25 '24 13:06 fabian-hiller