io-ts: Is there a way to write a codec that fails on additional properties?
Do you want to request a feature or report a bug? Question: Is there a way to write a codec that fails on additional properties?
const FruitOrAnimal = t.union([
t.strict({ fruit: t.string }),
t.strict({ animal: t.string })
]);
console.log(FruitOrAnimal.decode({ fruit: "banana", animal: "cat" }).isRight());
//prints 'true' but would like it to be 'false'.
Would like a decoder that fails this input type and interpret it as an “impossible state”. An input with either fruit or animal is fine but never both.
What is the current behavior? https://codesandbox.io/embed/8483r1pwq9
Which versions of io-ts, and which browser and OS are affected by this issue? Did this work in previous versions of io-ts? 1.8.5
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 25
- Comments: 24 (7 by maintainers)
So if there is exact type here, I think by doing something similar to what exact type does, instead of striping additional properties, make a slightly adjustment to the striping function and let it do the checking work, if any property was stripped, then we know for sure there is additional properties.
I wrote a small
excess type
that works exactly as exact type did, but instead of stripping properties, it reports error if any additional properties were found. It looks woking with intersection.I’ve test this a little bit, and I havn’t came with any problem.
https://codesandbox.io/s/inspiring-wright-u4wk9 open the codesandbox console to check output
Regarding this subject, I’m not worried about additional properties, but more worried about possible typos made to optional properties. Consider the following:
This will succeed and we won’t immediately notice that we had a typo in
versionx
(instead of version). Sorry for hijacking this thread, but is somewhat similar.Is there any way for
io-ts
to help in this regard?Just chiming in to tell you about my use case and why I would like to see excess property check. We’re using
io-ts
to parse and decode data tables in feature files (Cucumber). Some of our tables contain optional properties, but failure to spell these properties correctly will naturally lead to unexpected behavior. It would be beneficial to us if such would lead to instant feedback.I am also interested in this ticket, and I am not a big fan of adding an additional package/dependency only for fixing it. I use io-ts to validate api calls from client to the server (on the server I want to ensure that the client calls my API exactly with the types allowed, and not with any additional/different parameters). Because decode simply strips additional parameters, I cannot detect easily if those extra parameters were present. Honestly I find a bit deceiving that if you mark a type as exact or an intersection of exact types, decode still allows extra fields to be used without adding any error.
I’m using this library to validate the format of the API response, which I do not control.
So I’ve made the io-ts type for the API response and I expect the validation to fail, if some property have appeared in the response, which is not in the validation type.
Additionally, I’m using this io-told validation in the test, as a development utility to write typings. And then I need it to fail on some properties, which I did not include in the type.
Lastly, it is the original typescript functionality. If you attach type { foo: string } to a variable, you can not add additional properties.
@goooseman Why? Decoders main duty is trying to deserialize a (possibly larger) data structure into another, why additional fields should be a problem (if they are stripped anyway)?
I think it would be good to improve documentation on this. There are a number of users that expect
const a: { b: number } = { b: 1 /* nothing else */ }
behaviour, somewhat reasonably as this is also how TS behaves which means this issue will probably surface again. Explaining thatt.type
and friends implement structural typechecking (as TS does) and its implications in the README.md would help users a lot.I think this is a usability issue for
io-ts
that is unfortunate and it would definitely be good to help users to a solution. If the closest/best solution does not play well with other codecs it should still be provided (somehow) with a caveat. What can one reasonably expect if you want to disallow additional props and intersect with another structually checked type? That is in the runtime domain. I believe it would be best to be informed of this behaviour and be empowered to make the decision for myself on an as-needed basis.I would in general agree. However given that Io-ts provides exact/strict types, I think the current behaviour of decoding an exact type even when it has additional properties is deceiving. Either exact/strict types should also be part of io-ts-types, or (as I hope, since they are super useful) if they stay in io-ts the decode should allow you to detect if there are extra properties without relying on manually deep comparing the original object and the “right” part of the decoded one
Just pointing out that this is not true in general in TS, being it a “structural” type system. There are a few special cases where excess properties are checked, namely object literal assignments:
I did a POC of “excess” in
io-ts-types
here: https://github.com/gcanti/io-ts-types/pull/114It is mostly a porting of https://github.com/gcanti/io-ts/issues/322#issuecomment-513170377, but, as requested in #378, also applies the same “excess” check in the
.is
method.I’ve discussed that PR offline with @gcanti and I’m closing it, the reason being we prefer not to make it “official” for the moment, since “excess” doesn’t work well with all the codecs,
t.intersection
for example, and also because the exact behavior desired by different people is varying (e.g. checking for “excess” in.is
or not)It think this issue could now be closed since there are already many linked solutions available: please refer to https://github.com/goooseman/io-ts-excess by @goooseman or to my POC here if you want the
.is
excess checkOne of the key design choices of
io-ts
is (I believe) mapping 1:1 with the TS type system, and this to me looks also one of the main strengths compared to other solutions for parsing/validation. And, as we all know, “excess property checks” is not a feature of the TS types system (if not in some specific instances)At the same time I can understand the desire to have a drop in solution compatible with io-ts to obtain this behavior, and I think the best starting point could be to move @gcanti example from https://github.com/gcanti/io-ts/issues/322#issuecomment-513170377 into
io-ts-types