Search code examples
typescriptunion-types

Property does not exist when using union type in typescript


Suppose that I have two interfaces:

interface Box {
    x: number
    y: number
}

and

interface ColouredBox {
    x: number
    y: number
    colour: string
}

Assume for the purpose of this question, that I cannot change the interfaces.

Now when constructing objects, I have code like this:

let a: Box|ColouredBox = {x: 1, y: 2}
if( something ){
    a.colour = "Blue"  // Compilation Error
}

I get this error on a.colour = "Blue":

Error:(24, 26) TS2339: Property 'colour' does not exist on type 'Box'.

Why? Is this a limitation of the TS compiler? Other than completely reconstructing the object, is there a different workflow that I could use?


Solution

  • Using a Partial

    Instead of using a union type, you can try using a Partial

    let a: Partial<ColouredBox> = {x: 1, y: 2}
    

    The partial will set all the properties of the ColoredBox as optional.

    Live example here.

    Update:

    Eliminate an Interface

    If you only want the color part of the interface to be optional, you can eliminate one of the interfaces.

    interface Box {
      x: number;
      y: number;
      color?: string;
    }
    

    Then to determine if you're dealing with a colored box:

    if (box.color) { ... }
    

    Type Assertion

    If you stick to using both interfaces, you can specifically treat a as a ColouredBox using the as keyword (a.k.a. a Type Assertion).

    let a: Box | ColouredBox = { x: 1, y: 2 };
    (a as ColouredBox).colour = "Blue";