Wilhelmina Lohan
Wilhelmina Lohan

Reputation: 3043

Why explicit boolean checks change behavior of Type guards

Why does item instanceof TypeB === true behave differently then item instanceof TypeB and isTypeB(item) === true behave differently then isTypeB(item) where isTypeB(item): item is TypeB;?

const items: (TypeA | TypeB)[] = [];

items.forEach(item => {

  // instanceof explicit
  if (item instanceof TypeB === true) {
    // mouse over item -> TypeA | TypeB
    doWithB(item); // red squiggly
  }

  // instanceof implicit
  if (item instanceof TypeB) {
    // mouse over item -> TypeB
    doWithB(item);
  }

  // Type predicates explicit
  if (isTypeB(item) === true) {
    // mouse over item -> TypeA | TypeB
    doWithB(item); // red squiggly
  }

  // Type predicates implicit
  if (isTypeB(item)) {
    // mouse over item -> TypeB
    doWithB(item);
  }

});

This should be the same logic and developer preference. Is this a Typescript bug?

https://stackblitz.com/edit/typescript-type-predicates-scope-with-explicit-bool?file=index.ts

Upvotes: 1

Views: 46

Answers (1)

basarat
basarat

Reputation: 275917

Why does item instanceof TypeB === true behave differently then item instanceof TypeB

Simply because one is a valid type guard, whereas === true is not a valid type guard. TypeScript doesn't try to be smart as you can always break it, e.g. here is a function that returns true but changes state internally:

  const assign = (): true => {
    item = new TypeA();
    return true;
  }

  // instanceof explicit
  if ((item instanceof TypeB) === assign()) {
    // mouse over item -> TypeA | TypeB 
    doWithB(item); // Aren't you glad its an error
  }

Same for isTypeB(item) === true.

More on reporting it

TypeScript could make it valid, but isTypeB(item) by itself already works, and a contrived example you want to work, is not going to become an error without justification on why you need to write code like that.

Upvotes: 2

Related Questions