Search code examples
typescriptundefined

Passing Undefined to Optional Field


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.


Solution

  • 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).