Flow: `boolean` is incompatible with `true | false`

Created on 17 Jun 2017  路  6Comments  路  Source: facebook/flow

Flow does not let you pass a boolean where (true | false) is accepted.

// @flow

declare function foo(true | false): void
declare function bar(): (boolean)

foo(bar())

This fails with the following error:

6: foo(bar())
       ^ boolean. This type is incompatible with
3: declare function foo(true | false): void
                        ^ union: boolean literal `true` | boolean literal `false`

Why is this? I would expect boolean to be defined internally as just true | false, but that seems not to be the case.

feature request

Most helpful comment

If you have type T = true | false | "1" and f: boolean => () it seems reasonable to expect

const x = (t: T) => {
  if (x !== "1") {
    f();
  }
}

to typecheck.

All 6 comments

Indeed, boolean is a separate type. While it's possible to make boolean an alias of true | false, the question is, why would you even need that? What's the point of writing true | false instead of boolean?

why would you even need that? What's the point of writing true | false instead of boolean?

That's not the point; Flow is detecting a program as having an error when intuitively it shouldn't. boolean doesn't need to be an alias for true | false, but it definitely shouldn't be incompatible with it. Let me know if you need a clearer explanation!

Flow is detecting a program as having an error when intuitively it shouldn't

That does happen very often indeed. The problem is that fixing all of these case could be very very hard (not this particular one), but will give very little benefit.

So while this is definitely an improvement, this issue will always be very low priority.

If you have type T = true | false | "1" and f: boolean => () it seems reasonable to expect

const x = (t: T) => {
  if (x !== "1") {
    f();
  }
}

to typecheck.

I am hitting this now and it's a real problem.

why would you even need that? What's the point of writing true | false instead of boolean?

My use case is an overloaded function with return types dependent on a boolean argument:

type Check = ((true, number, string) => number) &
  ((false, number, string) => string)

const check: Check = (bool, a, b) => (bool ? a : b)

const n: number = check(true, 10, 'string') // works
const n2: string = check(true, 10, 'string') // correctly errors

const s: string = check(false, 10, 'string') // works
const s2: number = check(false, 10, 'string') // correctly errors

const getBoolValue = (): boolean => true
check(getBoolValue(), 10, 'string') // Errors with "boolean. Expected boolean literal `true`"

You can see the above in the flow REPL here.

Another Use Case: When you use a union type and want to distinguish between the cases.

type Modus = [false, null] | [true, null] | [true, string];

I was able to fix it by merging both null cases. However, I can imagine that there are cases where you want to separate two cases based (like for Redux Actions where you use constants for that)

Try Flow

Was this page helpful?
0 / 5 - 0 ratings

Related issues

danvk picture danvk  路  73Comments

xtinec picture xtinec  路  65Comments

sebmck picture sebmck  路  113Comments

TylerEich picture TylerEich  路  49Comments

STRML picture STRML  路  48Comments