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.
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)
Most helpful comment
If you have
type T = true | false | "1"
andf: boolean => ()
it seems reasonable to expectto typecheck.