Description
Recently I've been exploring ways to require that the optional
decoder be used for fields that are optional. From that process I've realized that I need to make a number of subtle design decisions related to how loosely or strictly a decoder needs to match a type. On the one hand, we should leverage typescript to help us write decoders that are as accurate as possible. On the other hand, I don't want the rules/guidelines around writing decoders to get too complicated, and I also don't want to be overbearing and prevent the user from writing the exact decoder they intend to.
With all that in mind, I've got a few examples of situations where I could change the library to more strictly fit decoders to types. Please respond with feedback to the three questions, plus any other concerns or observations you've got.
- Here are four decoders for the interface
AB
. All four decoders are valid and will compile without errors. In an ideal world, which of these decoders would you want to be valid, and which ones should produce an error?
interface AB {
a: string;
b?: number;
}
const decoderAB1 = object({
a: string(),
b: optional(number())
});
const decoderAB2 = object({
a: string(),
b: number()
});
const decoderAB3 = object({
a: string(),
b: union(number(), constant(undefined))
});
const decoderAB4 = object({
a: string()
});
- Ditto for
CD
. All four decoders are valid, but as a library user which ones would you want to be valid?
interface CD {
c: string;
d: number | undefined;
}
const decoderCD1 = object({
c: string(),
d: optional(number())
});
const decoderCD2 = object({
c: string(),
d: constant(undefined)
});
const decoderCD3 = object({
c: string(),
d: union(number(), constant(undefined))
});
const decoderCD4 = object({
c: string()
});
- Ditto for
E
.
interface E {
e: string | number;
}
const decoderE1 = object({
e: union(string(), number())
});
const decoderE2 = object({
e: string()
});