#How to get `exactOptionalPropertyTypes` to play nicely with object literals?

21 messages · Page 1 of 1 (latest)

shell bloom
#

I'd like to use this option for more strict code, but I'm not sure how to get it to work nicely with e.g. libraries that were not developed with this in mind.

My current problem is an options object that has a property signature { ssl?: <other type> } and I'd like to instantiate it with a big object expression. In that expression, I currently have ssl: <some_condition> ? <value> : undefined, which works at runtime but fails this new check.

Is there a way to exclude this key from the object entirely based on an inline condition when constructing the object expression, such that the type check will pass in this case?

cedar socket
#

you could use a spread object, but it might not look pretty to you depending on your preferences

rotund cairnBOT
#
that_guy977#0

Preview:```ts
// @exactOptionalPropertyTypes: true
type X = {opt?: string}
const x: X = {opt: undefined} // eOPT is enabled

const y: X = {
...(true ? {opt: ""} : {}),
...(true ? {opt: ""} : undefined),
...(true ? {opt: ""} : null),
}```

neon bobcat
#

I currently have ssl: <some_condition> ? <value> : undefined, which works at runtime but fails this new check.
@shell bloom That doesn't "work" at runtime: the ssl now exists in the object, so 'ssl' in obj will return true rather than false.

shell bloom
#

I know it has different behavior for some checks, but it works for a library that does if opts.ssl....

#

I understand why this option exists 🙂 but in this case, it currently works, and I'd like to figure out how to make it have the same behavior with more accurate object shape according to the types.

neon bobcat
#

That's the point, EOPT is specifically designed to distinguish {} from { key: undefined }. If you turn that on, you are essentially saying "these two aren't equivalent everywhere"

shell bloom
#

yes, I know!

#

I was asking if there was some way to specify 'don't actually set this key' in an inline object expression via some value, but there isn't

#

the spread object described above seems to be the only way

neon bobcat
#

Spread is the way to go yeah.

cedar socket
#

you could make a utility for it

neon bobcat
#

Cool, just making sure you know what you are getting yourself into, EOPT prevents a very specific set of errors that's largely irrelevant in most applications and causes more headaches.

shell bloom
#

yeah it looks like a giant mess especially because most libraries don't take this into account

#

the big one for me is my database driver, which when you set .values({a: foo, b: bar, ....}) has the same behavior for unset keys and undefined keys, but generates types that only allows optional well defined keys for nullable columns

neon bobcat
#

It's actually recommended for libraries to not take that into account, because people do write { key: undefined }, so the library should treat {} and { key: undefined } the same way if they want it to work like how a large portion of people write their code.

shell bloom
#

I am just looking at this option for the first time since arktype now recommends turning it on. And I immediately have 100+ errors in my application

#

ah yes, sorry, I mean library types are written as key?: valueType rather than key?: valueType | undefined

#

so even if undefined and unset have the same behavior, the types only allow one.

neon bobcat
#

Ah yeah.

#

FYI, you can spread a falsy value just fine, so instead of using a ternary like ...(condition ? { key: value } : {}), you can instead do ...condition && { key: value }.