ow
ow copied to clipboard
Is there a way for an object predicate to differentiate between key with value `undefined`, and key not present?
If we want to validate an object with optional parameters for a spread:
type Hotdog = {
length: number;
topping: string;
}
function patchHotdog(hotdog: Hotdog, patchBody: unknown): Hotdog {
ow(
patchBody,
ow.object.exactShape({
length: ow.optional.number,
topping: ow.optional.string,
})
)
return {
...hotdog,
...patchBody
}
// ERROR:
//TS2322: Type '{ length: number | undefined; topping: string | undefined; }' is not assignable to type 'Hotdog'.
// Types of property 'length' are incompatible.
// Type 'number | undefined' is not assignable to type 'number'.
// Type 'undefined' is not assignable to type 'number'.
}
This doesn't work, as ow will assert patchBody
as
type ValidatedPatchBody = {
length: number | undefined;
topping: string | undefined;
}
when really we want
type ValidatedPatchBody = {
length?: number;
topping?: string;
}
Which makes a difference, as js treats undefined value and no key differently when spreading:
const obj1 = { bar: 'foo', ...{} } // => { bar: 'foo' }
const obj2 = { bar: 'foo', ...{ bar: undefined } } // => { bar: undefined }
Unless I'm missing something, it doesn't look like ow
provides a way to do this out of the box.
In the mean time, I've worked around this by passing in an explicit type argument:
function patchHotdog(hotdog: Hotdog, patchBody: unknown): Hotdog {
ow<{length?: number, topping?:string}>(
patchBody,
ow.object.exactShape({
length: ow.optional.number,
topping: ow.optional.string,
})
)
return {
...hotdog,
...patchBody
} // IT OKAY
}
Unless I'm missing something, it doesn't look like ow provides a way to do this out of the box.
Correct. .optional
indicates the value is optional, not the key.
I think this use-case should be supported, but I don't have a clear idea on how right now.