Введение: Почему простая задача ломает код
Каждый разработчик, работающий с TypeScript, рано или поздно сталкивается с задачей: «Как преобразовать строку в число?». Казалось бы, что может быть проще? Но именно эта, на первый взгляд, тривиальная операция становится источником десятков багов, особенно на стыке фронтенда и бэкенда, где данные приходят из форм ввода, API или парсинга CSV.
На Stack Overflow вопрос «How to convert a string to number in TypeScript?» набрал десятки тысяч просмотров. И это не случайно. Разработчики тонут в нюансах: NaN, parseInt против Number(), потеря точности и неожиданное поведение с пустыми строками. В этой статье мы разберем топ ошибок при преобразовании строки в число в TypeScript и покажем, как их избежать. Вы узнаете, какой метод выбрать для конкретной задачи и как написать действительно надежный код.
Основные способы преобразования строки в число в TypeScript
Прежде чем говорить об ошибках, давайте вспомним инструменты, которые есть в арсенале TypeScript-разработчика. Каждый из них ведет себя по-своему, и выбор неправильного метода — первая и главная ошибка.
1. Функция Number()
Самый очевидный способ. Number(value) пытается преобразовать переданное значение в число. Если это невозможно, возвращает NaN.
const str: string = "42";
const num: number = Number(str);
console.log(num); // 42
const invalid: string = "hello";
const badNum: number = Number(invalid);
console.log(badNum); // NaN
2. Унарный плюс (+)
Короткий синтаксис, который делает то же самое, что и Number(). Лаконично, но может сбивать с толку новичков.
const price: string = "99.99";
const numericPrice: number = +price;
console.log(numericPrice); // 99.99
const empty: string = "";
const zero: number = +empty;
console.log(zero); // 0 — внимание, это частая ловушка!
3. parseInt() и parseFloat()
Специализированные функции для парсинга целых и дробных чисел. Они «откусывают» числовую часть от строки, игнорируя последующие символы.
const userInput: string = "123px";
const width: number = parseInt(userInput, 10);
console.log(width); // 123 — символы 'px' отброшены
const height: string = "45.67em";
const parsedHeight: number = parseFloat(height);
console.log(parsedHeight); // 45.67
4. Битовые операторы (~~, | 0)
Экзотический способ, который пришел из JavaScript. Работает только для целых чисел и отбрасывает дробную часть.
const str: string = "7.8";
const result: number = ~~str;
console.log(result); // 7 — дробная часть потеряна
Топ-5 ошибок при преобразовании строки в число в TypeScript
Теперь, когда мы разобрали инструменты, давайте посмотрим, где разработчики чаще всего спотыкаются. Эти ошибки — настоящие «грабли», на которые наступают даже опытные программисты.
Ошибка №1: Игнорирование NaN
Самая распространенная ошибка — не проверять результат на NaN. TypeScript не выдаст ошибку, если вы используете NaN в арифметических операциях или сравнениях, но результат будет неожиданным.
const input: string = "not a number";
const value: number = Number(input);
// Ошибка: NaN участвует в вычислениях
const total = value + 10;
console.log(total); // NaN
// Сравнение с NaN всегда ложно
if (value === NaN) {
console.log("Это не сработает никогда");
}
Как избежать: Всегда используйте isNaN() или Number.isNaN() для проверки. Второй вариант предпочтительнее, так как он не приводит нечисловые типы.
if (Number.isNaN(value)) {
console.error("Введено не число");
// Можно вернуть значение по умолчанию или показать ошибку
} else {
const total = value + 10;
console.log(total);
}
Ошибка №2: Путаница с parseInt и отсутствие radix
Функция parseInt принимает второй аргумент — систему счисления (radix). Если его не указать, parseInt может вести себя непредсказуемо, особенно со строками, начинающимися с "0".
// Без radix — опасный код
const octal: string = "077";
const withoutRadix: number = parseInt(octal);
console.log(withoutRadix); // 77 (в старых браузерах могло быть 63 — восьмеричное число)
// С radix — правильно
const withRadix: number = parseInt(octal, 10);
console.log(withRadix); // 77 — всегда 77
Как избежать: Всегда передавайте второй аргумент в parseInt(str, 10) для десятичной системы. Это убережет вас от багов, связанных с интерпретацией чисел в разных системах счисления.
Ошибка №3: Проблемы с пустыми строками и пробелами
Разные методы по-разному обрабатывают пустые строки и строки с пробелами. Number() и унарный плюс превращают пустую строку в 0, а parseInt — в NaN. Это может стать неожиданностью, если вы обрабатываете данные из форм.
const emptyStr: string = "";
const spaceStr: string = " ";
console.log(Number(emptyStr)); // 0
console.log(+spaceStr); // 0
console.log(parseInt(emptyStr, 10)); // NaN
console.log(parseFloat(spaceStr)); // NaN
Как избежать: Определите, какое поведение вам нужно. Если пустая строка — это ошибка, используйте parseInt и проверяйте на NaN. Если пустая строка должна означать 0 — можно использовать Number(), но тогда убедитесь, что это ожидаемое поведение в вашем контексте.
Ошибка №4: Потеря точности с большими числами
JavaScript (и TypeScript) использует 64-битный формат с плавающей точкой. Это значит, что целые числа больше Number.MAX_SAFE_INTEGER (9 007 199 254 740 991) теряют точность. При парсинге длинных строковых чисел вы можете получить неверный результат.
const bigNumberStr: string = "98765432109876543210";
const result: number = Number(bigNumberStr);
console.log(result); // 98765432109876540000 — точность потеряна!
Как избежать: Если вы работаете с большими числами (ID из базы данных, номера счетов), используйте тип bigint. Он поддерживается в TypeScript 3.2+.
const bigNumberStr: string = "98765432109876543210";
const bigResult: bigint = BigInt(bigNumberStr);
console