Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there any Typescript expressions `A` such that the truthiness of `A` is different from `!!A`?

In Javascript, almost all expressions (all expressions?) have a "truthiness" value. If you put an expression in a statement that expects a boolean, it will evaluate to a boolean equivalent. For example:

let a = 'foo'

if (a) {
  console.log('a is truthy!');
}
// Will print 'a is truthy!'.

In some workplaces it is common to coerce an expression in this situation into an actual boolean by negating it twice:

let a = 'foo'

if (!!a) {
  console.log('a is truthy!');
}
// Will print 'a is truthy!'.

My question: Is this merely a matter of style? Is it purely to communicate to someone reading the code that we really recognize that a is not a boolean, but that we intend to evaluate it as such anyway? Or do there exist any expressions or values of a where if (a) actually evaluates to a different boolean value than if (!!a)?

like image 849
Mark Meuer Avatar asked Aug 10 '18 14:08

Mark Meuer


People also ask

Is null Falsy typescript?

The null in TypeScript is a special value & also a data type. The value null represents the intentional absence of any object value. It is one of TypeScript's primitive values and is treated as falsy for boolean operations. The value of null is represented in using the literal null .

What is truthy in typescript?

Truthy - Typescript. Typescript. Truthy. JavaScript has a concept of truthy i.e. things that evaluate like true would in certain positions (e.g. if conditions and the boolean && || operators).

What is as any in typescript?

(this as any ) is just a Type Assertion that works on dev/compiling time and has no side effects on run time because it is purely a Typescript thing.

Which expression evaluates to true in JavaScript?

Logical AND (&&) Relational expressions always evaluate to true or false , so when used like this, the && operator itself returns true or false . Relational operators have higher precedence than && (and || ), so expressions like these can safely be written without parentheses.


2 Answers

Is this merely a matter of style? Is it purely to communicate to someone reading the code that we really recognize that a is not a boolean, but that we intend to evaluate it as such anyway?

See Why use if (!!err)?

Or do there exist any expressions or values of a where if (a) actually evaluates to a different boolean value than if (!!a)?

No, as long as a always refers to the same thing (for example, it is not a getter that returns random content). See the specification:

Logical NOT Operator (!)

  1. Let expr be the result of evaluating UnaryExpression.
  2. Let oldValue be ToBoolean(? GetValue(expr)).
  3. If oldValue is true, return false.
  4. Return true.

The if statement

  1. Let exprRef be the result of evaluating Expression.
  2. Let exprValue be ToBoolean(? GetValue(exprRef)).
  3. If exprValue is true, then
    • Let stmtCompletion be the result of evaluating the first Statement.
  4. Else,
    • Let stmtCompletion be the result of evaluating the second Statement.
  5. Return Completion(UpdateEmpty(stmtCompletion, undefined)).

Both, the logical NOT operator and the if statement call the ToBoolean function. As a result, there is no way that if (a) and if (!!a) are different (still assuming both as refer the same thing).

like image 28
str Avatar answered Sep 30 '22 22:09

str


The truthyness of a and !!a will always be the same.

ToBoolean is just a static lookup, and does not execute any user defined code at any step. Using ! applies ToBoolean, and negates the result. if also applies ToBoolean, and takes the result. Both don't really do much more. As double negation is the identity, and ToBoolean doesn't change anything if the input is already boolean, they will always be the same.

TL;DR; in pseudocode, "ToBoolean(a) === ToBoolean(booleanNot(ToBoolean(booleanNot(ToBoolean(a)))))".


Note that it is possible to mutate the variable on each lookup, and produce tests that may be confusing, but don't actually disprove the above. a is simply changed after the first evaluation - whether !! was used or not, makes no difference:

let x = 0;
let objectEnvironment = { get a() { return x++; } };
with(objectEnvironment){
  if (a) console.log("truthy?");
  if (!!a) console.log("double negated truthy?");
}

If you swap the use of a and !!a in above example, the output won't change. Note that with is an error in strict mode already, and should not be used. It only served to show that GetValue can be used to execute user-defined code. However, it's undetectable, whether logical not was used or not, so making a condition for it should not work.

like image 140
ASDFGerte Avatar answered Sep 30 '22 22:09

ASDFGerte