Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why TS is unsafe in unary arithmetic operations but not in binary ones?

In arithmetics the following is true: let 'a' be any positive real number, so:

-a = a*(-1)  

Typescript compiler seems to not reproduce arithmetic rules in a type-safe way. Look:

(I) Work as expected

Following lines produces this error message: "the left-hand side of an arithmetic operation must be of type 'any', 'number', 'big-int', or enum type"

const f = (a: string) => a*(-1)  // error
const g = (a: {}) => a*(-1)      // error

(II) Do not work as expected

In below scenario all arithmetic computation are unsafely perfomed with non-numerical types and no compile-time error is raised.


const f = (a: string) => -a
const g = (a: {}) => -a 

console.log(f('hi there')) // produces 'NaN' !
console.log(g('hi there')) // produces 'NaN'

console.log(g(2)) // produces -2

QUESTION

  • Why TS is not as safe in the unary operator as it is in the binary operator?

NOTES: TS version 3.7.2 / Type 'unknown' works as expected

like image 912
Flavio Vilante Avatar asked Jan 03 '20 04:01

Flavio Vilante


1 Answers

The ECMAScript specification states that the unary + and unary - operators both perform the abstract operation ToNumber() on their input expression:

12.5.6 Unary + Operator

NOTE The unary + operator converts its operand to Number type*.

12.5.6.1 Runtime Semantics: Evaluation

UnaryExpression : + UnaryExpression

  1. Let expr be the result of evaluating UnaryExpression.

  2. Return ? ToNumber(? GetValue(expr)).

12.5.7 Unary - Operator

NOTE The unary - operator converts its operand to Number type* and then negates it. Negating +0 produces -0, and negating -0 produces +0.

12.5.7.1 Runtime Semantics: Evaluation

UnaryExpression : - UnaryExpression

  1. Let expr be the result of evaluating UnaryExpression.

  2. Let oldValue be ? ToNumber(? GetValue(expr)).

  3. If oldValue is NaN, return NaN.

  4. Return the result of negating oldValue; that is, compute a Number with the same magnitude but opposite sign.

*emphasis added

TypeScript has no reason to impose arbitrary restrictions on the accepted types, since the primary intended usage, according to the specification, is to perform type conversion.


To address Emanuel Vintilă's comment on the question above:

Binary operators also perform type conversion

The specification does not use the same language, i.e.

[...] converts its operand to Number type

under MultiplicativeExpression; that is, while the multiplicative *, /, % operators do perform type conversion, it is not the primary intended usage for them.

like image 96
Patrick Roberts Avatar answered Oct 23 '22 04:10

Patrick Roberts