-1

I've been reviewing a case that looks like this:

loggedInUser$ = this.select().pipe(
    filter(({ user }) => toBoolean(user)),
    map(({ user: { firstName: f, lastName: l } }) => `${f} ${l}`)
);

Just curious whether we could always substitute !! in place of this method to get a boolean and whether. IIUC the semantics would always be the same?

In other words we should always be able to replace toBoolean(...) with !!?

The implementation looks like this:

// @internal
export function toBoolean(value: any): boolean 
{
  return value != null && `${value}` !== 'false';
}

Analysis

So based on the answers the difference is that !! returns true for 'false', but toBoolean() returns false for 'false'.

This is a bit subjective, but personally I feel that it's better to tell users to use !! than some other sugared approach, since we should be familiar with the Javascript basics / semantics first and then build out from that.

Thus if anyone wants 'false' to be false, then they have to implement that explicitly. The application in this case would be that someones name is actually 'false` and we want to allow that to be true.

Ole
  • 41,793
  • 59
  • 191
  • 359
  • 1
    Unless you post the implementation of "Akita `toBoolean`" (which I have never heard of) we cannot judge whether it is semantically equivalent to `!!`. – Bergi Mar 21 '19 at 21:13
  • 1
    You should always adapt your condition to the context of your problem. I think the best and more readable solution would be to use `user && user.firstName && user.lastName` – Kevin Pastor Mar 21 '19 at 21:14
  • I thought perhaps it would fit into a mathematical proof type category. In other words two parallel lines will never intersect? – Ole Mar 21 '19 at 21:14
  • 2
    related: [Is it 100% correct to replace !!someVar with Boolean(someVar)?](https://stackoverflow.com/a/38593659/1048572) – Bergi Mar 21 '19 at 21:15
  • 1
    Added the implementation to the question. – Ole Mar 21 '19 at 21:17
  • 4
    Akita's implement of [toBoolean](https://github.com/datorama/akita/blob/master/akita/src/toBoolean.ts) checks if the string representation of the value is neither `null` nor `"false"`. Therefore, `toBoolean("false")` and `!!"false"` would be different, as shown in [this stackblitz](https://stackblitz.com/edit/angular-f9t6xu?file=src%2Fapp%2Fapp.component.html). – ConnorsFan Mar 21 '19 at 21:17
  • Good comments - I updated the question with some additional curiosity WRT the correctness of using `!!` vs `toBoolean()` ...? – Ole Mar 21 '19 at 21:25
  • For example what if the users name was actually "false"? – Ole Mar 21 '19 at 21:28
  • @Ole It depends on what values you want to consider "true." The answers already give some examples of where it differs from standard boolean conversion, it's up to you which one is more correct for your purposes. – John Montgomery Mar 21 '19 at 21:29
  • The purposes part is what I'm concerned about. Initially I was thinking that the normal javascript conventions for false values apply (Like undefined, null, etc) and everything else is true (0, any valid string, etc.). I'm mostly concerned about `toBoolean()` giving a false positive for something that really should be true. – Ole Mar 21 '19 at 21:31
  • I'm also implementing a store and I feel as if telling users to use `!!` and apply general Javascript semantics is cleaner and easier to interpret and work with. In which case `false` is actually true. If users don't want `false` to be true they have to implement a custom check. – Ole Mar 21 '19 at 21:34

2 Answers2

3

No, your toBoolean and !! are not semantically equivalent. toBoolean depends on string serialisation, which is a rather weird way to cast a value to a boolean. Here are a few values that lead to different results:

toBoolean(0) == true
toBoolean('false') == false
toBoolean('') == true
toBoolean({toString(){return "false"}}) == false
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Just curious do you think it's better in general to use `!!`? Some people commented that it depends on "My" use case ... but Akita has 14K weekly downloads and personally I think people may see cases where 'false' is supposed to be true, although it is very low probability. Using `!!` solves that IIUC. – Ole Mar 21 '19 at 21:54
  • 1
    @Ole I don't think there's a general rule. I would prefer not to have to use any cast at all, and instead get passed booleans right away. If you need a conversion, you always need to adjust it to the use case. In your case, I'd go for `filter(({ user }) => user != null && typeof user.firstName == "string" && typeof user.lastName == "string")` to be extra safe, but depending on what you know about the input data you might be able to simplify. – Bergi Mar 21 '19 at 21:59
  • Thanks I like that better as well! – Ole Mar 21 '19 at 22:00
2

No, !! is not equivalent to toBoolean.

To explain a bit further, !! will always return a Boolean value MDN even has a note on the usage of !!:

It is possible to use a couple of NOT operators in series to explicitly force the conversion of any value to the corresponding boolean primitive. The conversion is based on the "truthyness" or "falsyness" of the value (see truthy and falsy).

The same conversion can be done through the Boolean function.

So you can always replace Boolean(x) with !!x, but what about toBoolean? Notice that toBoolean converts its parameter to a string and compares that to the string 'false', so there's at least one case where it's not the same:

function toBoolean(value: any): boolean 
{
  return value != null && `${value}` !== 'false';
}

console.log(Boolean('false'))
console.log(toBoolean('false'))

And to show a more subtle issue:

function toBoolean(value: any): boolean 
{
  return value != null && `${value}` !== 'false';
}

const foo = { toString: () => 'false' };

console.log(Boolean(foo))
console.log(toBoolean(foo))
Community
  • 1
  • 1
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331