sindresorhus/eslint-plugin-unicorn

Rule proposal: no-implicit-conversion

axetroy opened this issue · 3 comments

Description

When using the +/- operator with strings and numbers.

There are many traps here, and things can go wrong.

e.g.

let result = '5' + 3;
console.log(result); // '53' - String concatenation

let result = '5' - 3;
console.log(result); // 2 - The string is converted to a number

result = 3 + '5';
console.log(result); // '35' - Still string concatenation

let result = '10' - 3;
console.log(result); // 7 - The string '10' is converted to the number 10

result = '5' - '2';
console.log(result); // 3 - Both strings are converted to numbers and then subtracted

I know, no one would write code like this in the real world

But there will be the following situation

function foo() {
  // ...other logic
  return "5"
}

// ... other logic

const bar = foo() + 5 // ❌

We should check that left and right expression are of the same type to avoid implicit conversion.

It is feasible when we can infer its type, skip check when found any/unknown/never.

There is no possibility of false positives

Fail

Plus operator:

const foo = "5" // numberic

// ... other logic

const bar = foo + 5 // ❌
function foo() {
  return "5"
}

// ... other logic

const bar = foo() + 5 // ❌

Minus operator:

const foo = "10"

// ...other logic

const bar = foo - 5 // ❌

Type Annotation:

let foo: string

// ...other logic

const bar = foo - 5 // ❌
let foo = (): string => {}

// ...other logic

const bar = foo() - 5 // ❌
function foo (bar: string) {
  bar - 5 // ❌
}

Pass

const foo = "5"

// ... other logic

const bar = Number(foo) + 5 // ✅
function foo() {
  return "5"
}

// ... other logic

const bar = Number(foo()) + 5 // ✅

Minus operator:

const foo = "10"

// ...other logic

const bar = Number(foo) - 5 // ✅

Proposed rule name

no-implicit-conversion

Additional Info

No response

This is hard to detect, but

1e13 - new Date(); // -> number

1e13 + new Date(); // -> string

If the code is in TS this is redundant, so the “type annotation” examples shouldn’t be considered.

For the rest, this would only work in the limited cases where the value (and therefore its type) is defined locally. It kinda makes sense as a rule but also people who care about this just use TypeScript. By this I mean that outside TS people generally take advantage of JS’ dynamicity and don’t like the verbosity of Number(str) - 1.

The only scenario where this would actually be beneficial (i.e. prevent bugs) is on str + number, but it feels like this rarely happens when str is declared locally.

Just my 2c, this rule wouldn’t affect me as I use TS almost exclusively.

TypeScript can detect this. If user use JavaScript, they need to tolerate the type-safe problems about JavaScript. IMO, ESLint should not repeat the functions belonging to TS.