Home > Software engineering >  The conditional expression type will always evaluate to the union of the two in TypeScript
The conditional expression type will always evaluate to the union of the two in TypeScript

Time:08-29

Conditional expression gives odd behaviour.

Example:

const value = false
const result = value ? 1 : 2  // <--   result is 1 | 2, not 2

My question, why does The conditional expression type always evaluate to the union of the two in TypeScript

CodePudding user response:

TypeScript does not support this. But, if you make it as a part of one data structure, TS will help you:

type True = {
    value: true,
    num: 1
}
type False = {
    value: false,
    num: 2
}

type Result = True | False

declare const result: Result;

const { value, num } = result

if (value) {
    num // 1
} else {
    num // 2
}

Or you can create a function and overload it:



function fn(cond: false): 2
function fn(cond: true): 1
function fn(cond: boolean) {
    return cond ? 1 : 2
}

fn(true) // 1
fn(false) // 2

CodePudding user response:

This behavior is considered intentional, as mentioned in microsoft/TypeScript#14206. Related suggestions to change this sort of behavior, at microsoft/TypeScript#39995 and microsoft/TypeScript#43040, are currently marked as "Awaiting More Feedback", meaning that if you care enough to see this changed you might want to go to those issues and describe your use case, why it is compelling, and why existing workarounds are not sufficient. I don't think this will have much of an effect, but it probably wouldn't hurt.


In order for false ? 1 : 2 to be considered of type 2, the compiler would need to perform control flow analysis for reachability inside of conditional/ternary operator expressions.

No such analysis is performed, so the compiler assumes that both branches of a conditional expression are reachable, and thus the expression's type is always the union of the types in each expression.

Control flow analysis is performed for conditional statements, although what you get is a reachability error and not narrowing:

function foo() { // still returns 1 | 2, but:
    if (false) {
        return 1; // error! Unreachable code detected!
    } else {
        return 2;
    }
}

But again, this does not happen for conditional expressions. Your question is: why?


The control flow analysis you want to see here wouldn't be free; it would impose a certain amount of performance penalty for each conditional expression in a code base. So the question is: how often do people write real-world code of the form x ? y : z where x is known at compile time to be either truthy or falsy, and is it often enough that adding the extra analysis would pay for itself?

In microsoft/TypeScript#39995, a TS team member says

Some use cases that aren't just code no one would reasonably write (e.g. true ? x : y or its equivalents) would be nice to give this some motivation. Operating on values that are known to be exactly true or false is relatively rare.

So the authoritative answer here seems to be that the TS team believes this sort of code is neither common nor reasonable, and thus it's not worth adding in extra control flow analysis to handle it.


Again, if you feel differently and want to see this change, you might want to go to the relevant GitHub issues and explain why, including a compelling reason for why someone might reasonably write such code, especially if you can find examples of existing code bases that use this enough to be worth the added compile times. But again, I wouldn't get your hopes up about seeing this actually change, since there are lots of longstanding open feature requests with more community engagement than those. Oh well. At least now you know why it is this way.

Playground link to code

  • Related