'TypeScript: No error when checking an union type

We have a function:

const fun = (): string => "hey";

We have an union type:

type Fruit = "banana" | "orange" | "apple";

The TS compiler won't allow this:

const check = (fruit: Fruit) => {
    if (fruit === "mango") {
        ...        ^^^^^ This condition will always return 'false' since the types 'Fruit' and '"mango"' have no overlap.
    }
}

But it does allow this:

const check = (fruit: Fruit) => {
    if (fruit === fun()) {
        ...       
    }
}

My question is why?



Solution 1:[1]

The return type of fun is string. You're allowed to use === (and !==) to compare a string operand with a string literal operand, so fruit === fun() is perfectly valid. (It's important that it is, since it's part of how you write a type guard.)

But "mango" is a compile-time constant value that's definitely not a member of Fruit, so TypeScript is warning you proactively that the comparison is pointless; it'll never be true.

You'd get the same error if fun's return type were "hey" rather than string:

const fun1 = (): string => "hey";
const fun2 = (): "hey" => "hey";

type Fruit = "banana" | "orange" | "apple";

const check0 = (fruit: Fruit) => {
    if (fruit === "mango") {
        // ^??? This condition will always return 'false' since the types 'Fruit' and '"mango"' have no overlap.(2367)
    }
};

const check1 = (fruit: Fruit) => {
    if (fruit === fun1()) {
        // ^?? works
    }
};

const check2 = (fruit: Fruit) => {
    if (fruit === fun2()) {
        // ^??? This condition will always return 'false' since the types 'Fruit' and '"hey"' have no overlap.(2367)
    }
};

Playground

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 T.J. Crowder