Home > other >  Why does typescript show an error on this scenario with a union type?
Why does typescript show an error on this scenario with a union type?

Time:06-10

On this scenario:

type Type = {
    a: string;
    b: string;
} | {
    a: number;
    b: number;
};

const func = ({a, b}: Type): string => {
    if (typeof a === 'string') {
        return b;
    }

    return 'w/e';
}

func({a: 1, b: 'w/e'});

I get an error on return b; stating

Type 'string | number' is not assignable to type 'string'.

  Type 'number' is not assignable to type 'string'.

From what I understand by the error, Typescript interprets the Type type as

type Type = {
    a: string | number;
    b: string | number;
};

, but even if that is the case, why can't I call the func function with a string and a number?

The error on the call states

Argument of type '{ a: number; b: string; }' is not assignable to parameter of type 'Type'.

  Type '{ a: number; b: string; }' is not assignable to type '{ a: number; b: number; }'.

    Types of property 'b' are incompatible.

      Type 'string' is not assignable to type 'number'.

(ts version: 4.7.2)

Playground link

The function call with the wrong types was just to test my hypothesis on why I get the previous error. Why do I get an error at return b; is what I don't understand.

CodePudding user response:

TS cannot tract the relationship of a and b after you destruct them, so they both be inferred string | number. TS 4.6 introduced a limited control flow analysis for destructing, which only applies to discriminated union.

CodePudding user response:

Ok, the answer is Discriminated Unions. I have to use a discriminant, a common property in each element of the union. That, discriminant, property:

  1. Has to be a primitive type, and
  2. Has to have a specific value and not that value's type. e.g. isPrimary: true, not isPrimary: boolean.

Then I can check for that property's value to assume the other properties' types.

Also, in Typescript versions < 4.6, If i have an object with a type specified as above, If i destructure it, then the new variables are considered independent and I will continue getting an error similar to the initial example. Destructuring works in version 4.6 or higher.

Helpful links:

Thank you @Austaras and @coglialoro

  • Related