io-ts
io-ts copied to clipboard
How to properly encode an optional field in a type?
📖 Documentation
I'm unable to figure out how to encode an optional field in an interface. For example, in TypeScript I have this type:
export type Filter = {
type: string
value: string|null
target?: string|null
}
I want to create the same type in io-ts, so tried the following:
export const IOFilter = t.type({
type: t.string,
value: t.union([t.string, t.null]),
target: t.union([t.string, t.undefined, t.null]),
})
export type Filter = t.TypeOf<typeof IOFilter>
But this new Filter
is not the same as the original one. A structure missing the target
field is no longer compatible:
// type error that `target` is missing
const a : Filter = {
type: 'name',
value: 'abc'
}
How do I create an optional field?
t.type
expects all of the specified keys to exist. To make a codec for a record with optional properties, use t.partial
.
These two codecs can be intersected to get what you're looking for:
const FilterC = t.intersection([
t.type({
type: t.string,
value: t.union([t.string, t.null])
}),
t.partial({
target: t.union([t.string, t.null, t.undefined])
})
])
type Filter = t.TypeOf<typeof FilterC>
const a: Filter = { // <-- typechecks!
type: 'name',
value: 'abc'
}
I am fairly certain you need to use the partial operator. I had the need for optional structures so mine looked like this where my whole IOFilter would be optional.
The union operator is like a OR condition if your structure might have this or that type.
export const IOFilter = t.partial({
type: t.string,
value: t.union([t.string, t.null]),
target: t.union([t.string, t.undefined, t.null]),
})
In your case this might work but I have not tested.
export const IOFilter = t.partial({
type: t.string,
value: t.partial(t.string),
target: t.partial(t.string),
})
'''
I have tried the proposed solution by @0x706b , and works great for optional properties.
However, the union types with null
are inferred as string
, do you know a possible solutions for this?
Seems they have updated their SDKs over time and seems this is no longer possible
@edaqa-uncountable cheers for the question and @0x706b cheers for the answer! 🙌
Should we close this as resolved? 🤷