Есть ли способ в TypeScript предупредить о 1 + 1 = 11?

JavaScript полон таких предостережений:

const arr = [1, 2, 3]

for (const i in arr) {
  console.log(i + 1)
}

Ожидаемый результат неопытного JS-разработчика будет 1 2 3, но на самом деле это 01 11 21.


Похоже, что TypeScript по умолчанию не предупреждает о конкатенации строк и чисел, есть ли способ добиться этого?

Если быть более точным: как я могу получить предупреждения о таких случаях, как '1' + 1


person Limon Monte    schedule 05.08.2019    source источник
comment
Вы имеете в виду помимо переноса добавления в функцию? В любом случае вы можете подумать, что компилятор как минимум предупредит вас об использовании for...in в массиве...   -  person Jared Smith    schedule 05.08.2019
comment
Я имею в виду всегда, независимо от места, т.е. в этом простейшем случае: console.log('1' + 1)   -  person Limon Monte    schedule 05.08.2019
comment
"" + 1 разрешено в JS, поэтому оно разрешено в TS. console.log() принимает как строки, так и числа, поэтому здесь нет ошибки. Однако, если вы попытаетесь обработать i + 1 как число, вы получите ошибку.   -  person Aaron Beall    schedule 05.08.2019
comment
Извините за использование console.log выше, это полностью выходит за рамки моего вопроса. Очень хотелось бы получать предупреждения о таких случаях: '1' + 1.   -  person Limon Monte    schedule 05.08.2019
comment
Ни в коем случае, это было предложено и отклонено. eslint или tslint — ваш единственный вариант.   -  person artem    schedule 05.08.2019
comment
tslint был устарел, возможно, вы знаете, какое eslint правило мне следует использовать ?   -  person Limon Monte    schedule 05.08.2019
comment
@LimonMonte IDK, если он уже перенесен на ESLint или нет, но вот что вы хотите   -  person Jared Smith    schedule 06.08.2019
comment
@AaronBeall Это более тонко, чем это ... такие утверждения, как X, разрешены в JS, поэтому они разрешены в TS, как правило, либо вводит в заблуждение или не соответствует действительности. Вопрос в том, является ли использование в JS скорее ошибкой, чем допустимым кодом; в этом случае так много реального кода JS использует такие конструкции, как console.log("There are " + files.length + " files"), что сопровождающие TS не думают, что здесь стоит быть более строгим.   -  person jcalz    schedule 06.08.2019
comment
@jcalz Не могу с этим поспорить, это более тонко, чем я сказал. Спасибо за лучшее объяснение. :)   -  person Aaron Beall    schedule 06.08.2019


Ответы (3)


ОБНОВЛЕНО ДЕЙСТВИТЕЛЬНЫЙ ОТВЕТ Используйте правило @typescript-eslint/restrict-plus-operands. Оба операнда должны быть либо строками, либо числами, но не сочетанием того и другого:

Конфигурация eslint из https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage

{
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "project": "./tsconfig.json"
  },
  "plugins": ["@typescript-eslint"],
  "rules": {
    "@typescript-eslint/restrict-plus-operands": "error"
  }
}

ОРИГИНАЛ

В TS Lint есть правило «prefer-template», хотя я не пробовал его с этим сценарием. Это должно работать, так как TypeScript видит переменную i как строковый тип.

https://palantir.github.io/tslint/rules/prefer-template/< /а>

Это правило потребует, чтобы вы сделали следующее, чтобы конкатенация работала:

console.log(`${i}1`);

Это должно как минимум сигнализировать разработчику, что он пытается выполнить конкатенацию.

К вашему сведению, TS Lint устаревает в пользу ES Lint, хотя я еще не перевел ни один из своих проектов на этот инструмент.

ОБНОВЛЕНО ES Lint имеет такое же правило: https://eslint.org/docs/rules/prefer-template

person ps2goat    schedule 05.08.2019
comment
Спасибо @ps2goat. Хотя prefer-template помогает в таких случаях, как console.log('1' + 1), он недостаточно умен, чтобы справляться с немного более сложными случаями, такими как const a = '1'; console.log(a + 1). - person Limon Monte; 05.08.2019
comment
Ты прав. Я теперь тоже разочарован :( - person ps2goat; 06.08.2019
comment
@LimonMonte — добавлено новое правило, которое я тестировал на своей машине. - person ps2goat; 06.08.2019
comment
Спасибо @ps2goat, это именно то, что я искал! Я обновил ваш ответ, чтобы скопировать и вставить friednly eslint config. Спасибо, друг, теперь мой проект более защищен от неожиданных результатов! - person Limon Monte; 06.08.2019

TS Lint может защитить от неправильного использования for..in. https://palantir.github.io/tslint/rules/forin/

person Daniel A. White    schedule 05.08.2019
comment
Спасибо, но я спрашиваю не только про for..in, а про общие случаи, т.е. '1' + 1 - person Limon Monte; 05.08.2019
comment
Кроме того, tslint был устарел, я бы предпочел не использовать устаревшие линтеры. . - person Limon Monte; 05.08.2019

Вы объединяете имя свойства массива, а не его значение. Это связано с тем, что for...in повторяет свойства объекта. Я думаю, что вы пытаетесь сделать следующее:

const arr = [1, 2, 3]

for (const i in arr) {
  console.log(arr[i] + 1)
}

Вы всегда можете написать туда некоторый код для проверки типов входных данных, но важно сначала понять цикл for...in — вот некоторые документация по for...in использованию массивов

You could use typeof to do a simple type check in your function:

function doConcat(operand1, operand2) {
  if (typeof operand1 !== typeof operand2) { //simple typeof check
    console.log(`Cannot concat type: ${typeof operand1} with type: ${typeof operand2}`);
    return;
  }
  return operand1 + operand2;
}

const arr1 = [1, 2, 3]; //Should work - adding 2 numbers
for (const i in arr1) {
  console.log(doConcat(arr1[i], 1));
}

const arr2 = ['a', 'b', 'c']; //Should bomb - trying to concat number and string
for (const j in arr2) {
  doConcat(arr2[j], 1);
}

person Tom O.    schedule 05.08.2019
comment
Я считаю, что не смог правильно задать вопрос, дело не в том, как работает for...in, а в объединении чисел и строк. Конкатенация чисел и строк может привести к неожиданным результатам, я бы хотел этого избежать. - person Limon Monte; 06.08.2019
comment
попался ... я обновлю свой ответ, чтобы отразить это - person Tom O.; 06.08.2019