TypeScript: Boolean() cannot be used to perform a null check
TypeScript Version: 2.4.0
Apologies for today’s issue raising binge.
Code
// Compiles
const nullCheckOne = (value?: number) => {
if (!!value) {
return value.toFixed(0);
}
return '';
}
const nullCheckTwo = (value?: number) => {
if (Boolean(value)) {
// Object is possibly 'undefined'
return value.toFixed(0);
}
return '';
}
Expected behavior: Both examples compile.
Actual behavior:
The latter example fails w/ Object is possibly 'undefined'.
Explanation
To my knowledge !!value and Boolean(value) are equivalent. I’m wondering what is the reason behind not supporting the second case. One reason I can think of would be an imported, non-typescript module, globally overriding it to something like: Boolean = (value) => !value.
About this issue
- Original URL
- State: open
- Created 7 years ago
- Reactions: 71
- Comments: 22 (7 by maintainers)
Commits related to this issue
- Add truthy type guard This adds an explicit type guard for truthiness. Generally you could use the `Boolean` constructor, but typescript doesn't treat that as a type guard right now (see [#16655](htt... — committed to ericmakesapps/fast-ts-helpers by ericbf 4 years ago
- resolve #16655; Boolean() can be type-guard for null checks — committed to gfx/TypeScript by gfx 8 months ago
- Add truthy type guard This adds an explicit type guard for truthiness. Generally you could use the `Boolean` constructor, but typescript doesn't treat that as a type guard right now (see [#16655](htt... — committed to ericmakesapps/fast-ts-helpers by ericbf 4 years ago
- Add truthy type guard This adds an explicit type guard for truthiness. Generally you could use the `Boolean` constructor, but typescript doesn't treat that as a type guard right now (see [#16655](htt... — committed to ericmakesapps/fast-ts-helpers by ericbf 4 years ago
- Add truthy type guard This adds an explicit type guard for truthiness. Generally you could use the `Boolean` constructor, but typescript doesn't treat that as a type guard right now (see [#16655](htt... — committed to ericmakesapps/fast-ts-helpers by ericbf 4 years ago
One common pattern using the boolean constructor is
.filter(Boolean)to remove falsy values from an array (includingnullandundefined).I think the “Awaiting more feedback” label can be removed, as tons of people seem to have this issue.
For anyone else running into the specific case of
Array.filter(Boolean), adding an overload forArray.prototype.filter()works great. I’ve tested this on 4.1.2 and https://github.com/microsoft/TypeScript/issues/31551#issuecomment-495201128 doesn’t seem to be present anymore. PatchingBooleanitself should work too, but I haven’t tried that.Another pattern is using
Boolean()along with&&- a common pattern for example in embedded JS expressions in JSX with React:https://codesandbox.io/s/falling-https-zvg2xv?file=/src/App.tsx
In the first example, the
0is rendered on the screen because it is falsey:To avoid this, the
Boolean()constructor is used to convert the number on the LHS of the&&to a boolean, but this causes a problem with the types:If the
Boolean()constructor behaved the same way that!!(double negation) did, this wouldn’t be an issue.Also affects strings:
Alternatives
There are alternatives to doing this:
But sometimes the
Boolean()option may be desirable because of its expressiveness.@Kovensky - that is a good point.
filteras it currently stands however, can’t be used to implement the type guards either. Both of the examples below infer to(number | undefined)[]. Would also be really cool to address it.This was reverted due to it causing a breaking change in 3.5. The simple repro looks like this:
There might be something wrong in generic inference, but it’s not yet clear. We’ll need this scenario to work before adding it back in.
Another workaround (playground link):
For anybody using @Etheryte’s great tip from https://github.com/microsoft/TypeScript/issues/16655#issuecomment-797044678 you may also want to extend the
ReadonlyArrayinterface with the same fix:It’s not supported because no one has done the work to support it yet.
In general we don’t account for this. Literally anything in the global scope could be mutated to be something different and it’d be insane to say Well you can’t use
substrbecause maybe someone messed with it.I think we could replace the signature with
which is almost correct (it fails to do the right then in the
elsecase whenxis0coming from a non-literal numeric type).I’ve literally never seen someone use
Booleanlike this, though. Is there any difference betweenif (value)andif (Boolean(value))?Nice one @Etheryte, thank you!
Here’s a solution that doesn’t require importing/defining a function, nor overloading a prototype. Verbose as hell, but 🤷
cool! btw, what’s the difference between your example and this one?:
Both these scenarios right now still break. I found a temporary workaround with
However it would be nice not to need the type guard. Is there any hope for that 😃?