Typescript: "This condition will always return 'false'" but returns true at runtime

Created on 22 Aug 2018  路  20Comments  路  Source: microsoft/TypeScript

TypeScript Version: 3.1.0-dev.20180818

Code

function sanityCheck(s: string): string {
    return s == 0 ? "I must be going insane" : "I'm fine";
}
console.log(sanityCheck(""));

Expected behavior:

Error message is 100% accurate.

Actual behavior:

src/a.ts:2:9 - error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.

The == operator in JavaScript converts its arguments -- some developers apparently rely on this behavior (not naming names but I noticed this in real JavaScript code that I pasted into a TypeScript file).
The error message might recommend using an explicit conversion such as Number(s) to get this to compile in TypeScript.

CC @DanielRosenwasser

Bug Error Messages

Most helpful comment

Is this not getting fixed?

All 20 comments

Yeah, we discussed == and != making the statement technically incorrect and decided to wait for the first bug report before addressing it.

I think just using the old error message is probably fine.

I got this error Operator '==' cannot be applied to types 'string' and 'number'. in Stackblitz.
https://stackblitz.com/edit/typescript-vwakj2

EDIT : Sorry, Typescript current version on Stackblitz shouldn't be 3.1.x

@HZooly That links to a document that doesn't use == anywhere?
Regardless, the solution is probably to be more explicit, and convert the string to Number(s) or the number to String(n), then use ===.

@andy-ms Sorry my snippet wasn't saved! Now it has been updated :)

I get the same error message for the following code:

image

image

@JohnPool See #9998

Thank you for pointing me to this interesting discussion!

I get this very annoying bug even with === in the following code snippet (see this stackblitz). The variable is set to an enum value and modified in a callback:

enum MyEnum {
  Value1,
  Value2,
  Value3
}

export class AppComponent {

  constructor() {
    this.doProcess();
  }

  doProcess() {
    let value: MyEnum;
    value = MyEnum.Value1;

    [1, 2, 3].forEach(x => {
      if (x > 1) {
        value = MyEnum.Value2;
      }
    });

    // The following condition evaluates to 'true'
    // but it is underlined in red with "This condition will always return 'false'..."
    if (value === MyEnum.Value2) {
      console.log("Hello world");
    }
  }
}

@ConnorsFan See #9998

@andy-ms The error goes away when I initialize the value as a number. I don't know if that is a recommended workaround:

let value = +MyEnum.Value1;

May be better to write MyEnum.Value1 as MyEnum because that at least specifies it as MyEnum rather than number.

@andy-ms I don't understand your last comment. Maybe I should add that the bug is also present if I do this:

let value: MyEnum;
value = MyEnum.Value1;

In other words, I don't know how to make the code work when value is of type MyEnum.

If you write +MyEnum.Value1 it's a number and could be passed to a function expecting a different enum. If you write MyEnum.Value1 as MyEnum it stays MyEnum and can't be used as an instance of a different enum.

OK, it works. Sorry, I had misread you previous comment. I didn't think that you meant as MyEnum literally in code.

I am having this issue in my generic isEqual function which the user can opt in to loose type check.

const myBool = true;
const myNumber = 1;
if (myBool == myNumber) {
    // will be reached
}

I have a similar scenario. Here is the minimal reproduction:

enum types {
  type1 = 'type1',
  type2 = 'type2'
}

class A {
  private h: types = types.type1;

  private a() {
    this.h = types.type2;

    this.b();
    // Actual error here: the method b changes h to types.type1. But typescript thinks this.h would always be types.type2.
    if (this.h === types.type1) { // This condition will always return 'false' since the types 'types.type2' and 'types.type1' have no overlap.

      console.log('hello')
    }
  }

  private b() {
    this.h = types.type1;
  }
}

See it live here: https://stackblitz.com/edit/typescript-qvs8ov

Is this not getting fixed?

I started to use @typescript-eslint/strict-boolean-expressions after I found a silly mistake in my code that could have costed me a lot of money, as I did a numberOrUndefinedVar ? X : Y, and 0 was not intentionally falling into Y, and it was making hundreds of DB calls.

This rule is very good, but, doesn't work very good with TS due to a current fact: If you want to check a falsy value (e.g. empty string and undefined), with == false, TS will throw This condition will always return 'false' since the types 'string | undefined' and 'boolean' have no overlap.ts(2367).

I have made, before this == false idea, a question in Stackoverflow about it, how to check for falsy value using this rule. While the two current answers are valid, they really aren't good to use outside your own code, where you know why you are using it and won't need to comment why you did those strange workarounds.

So, == false should be TS friendly, as it works as expected in JS.

Current TS version: 4.1.2

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jbondc picture jbondc  路  3Comments

kyasbal-1994 picture kyasbal-1994  路  3Comments

Antony-Jones picture Antony-Jones  路  3Comments

remojansen picture remojansen  路  3Comments

wmaurer picture wmaurer  路  3Comments