I have the following approach for dealing with passing down potentially undefined objects into optional properties:
type Foo = {
opt?: string
}
const opt = Math.floor(Math.random() * 2) == 0 ? "Hello" : undefined
const bar: Foo = {
}
if(opt !== undefined){
bar.opt = opt
}
Seems a bit clunky- using an if statement and then assigning inside that. Is there a more idiomatic Typescript-y way to do it? I tried this:
type Foo = {
opt?: string
}
const opt = Math.floor(Math.random() * 2) == 0 ? "Hello" : undefined
const bar: Foo = {
opt
}
But that results in the following error flagged in my VSCode IDE:
Type 'undefined' is not assignable to type 'string'.
Update: This behaviour is as intended due to the Typescript exact optional property types option, which I have switched on.
There is a difference between:
type Foo = {
opt?: string
}
// key opt might exist or not
and
type Foo = {
opt: string | undefined
}
// key opt always exists, but its value might be undefined
or finally
type Foo = {
opt?: string | undefined
}
// key might exist or not, if it exists can still be undefined
You first have to decide which of those designs you want, all are fine.
The common check for a property:
let isdefined = !!o.opt // test if property opt exists
behaves equal for o1 and o2 here:
o1 = { opt: undefined }
o2 = { }
let isdefined = !!o1.opt // false
let isdefined = !!o2.opt // false
Certainly of opt is set they also behave the same way.
That said, it is often simpler to write
If it is ok for you that opt might be undefined, you can make your assignment code nicer:
bar.opt = opt // no problem if opt is undefined
if it really is relevant that the key opt does not exist, you need your code:
if(opt !== undefined){
bar.opt = opt
}
So you have to decide. I suggest you allow undefined as value, since that simplifies assignment code and the access the property is usually the same code as shown above.
Finally, the error message
const bar: Foo = {
opt
}
is caused by the fact that your opt variable is of type (string | undefined). The compiler raises the issue that it can be undefined: You assignment of
{ opt }
is shorthand for
{ opt: opt }
but here, opt is interpreted as property key and undefined cannot be converted into a property key string (a number for instance can).