Avatar ·

Как преобразовать строку в число в TypeScript? Все способы и нюансы

Всем привет! Я только начал изучать TypeScript и столкнулся с простой, казалось бы, задачей. У меня есть переменная, которая приходит из формы или из localStorage, и она всегда имеет тип string. Мне нужно выполнить с ней математические операции, но TypeScript ругается. Вот пример моего кода: ```typescript const userAge: string = "25"; const nextYearAge = userAge + 1; // Результат: "251", а не 26! console.log(nextYearAge); // Выводит "251", потому что произошла конкатенация строк ``` Я понимаю, что в JavaScript есть несколько способов преобразовать строку в число: `parseInt()`, `parseFloat()`, `Number()`, унарный плюс `+`. Но какой из них лучше использовать в TypeScript? И есть ли какие-то TypeScript-специфичные методы? Меня интересуют следующие моменты: 1. Какой способ самый надёжный и производительный? 2. Как правильно обрабатывать случаи, когда строка содержит не только цифры (например, "123abc" или "abc123")? 3. Нужно ли использовать какие-то дополнительные проверки типов или утверждения (type assertions) в TypeScript для безопасности? 4. Как быть с числами с плавающей точкой и большими числами? Буду благодарен за подробное объяснение с примерами. Хочется понять не только "как", но и "почему" стоит использовать тот или иной подход в разных ситуациях. <<>>

Основные способы преобразования строки в число в TypeScript

В TypeScript, как и в JavaScript, есть несколько способов конвертации строки в число. Выбор правильного метода зависит от контекста и требований к обработке ошибок. Рассмотрим каждый из них подробно.

1. Функция Number() — универсальный способ

Это самый явный и предсказуемый способ. Функция Number() пытается преобразовать переданное значение в число. Если преобразование невозможно, возвращается NaN (Not a Number).

const str: string = "42";
const num: number = Number(str); // 42

const invalid: string = "hello";
const result: number = Number(invalid); // NaN

// Для TypeScript важно: тип возвращаемого значения — number, но может быть NaN
console.log(typeof result); // "number"
console.log(isNaN(result)); // true

2. Унарный плюс + — краткий синтаксис

Это сокращённая форма вызова Number(). Работает идентично, но короче в написании.

const str: string = "3.14";
const num: number = +str; // 3.14

const empty: string = "";
const emptyNum: number = +empty; // 0 (обратите внимание!)

Важный нюанс: пустая строка "" при преобразовании через + или Number() даёт 0, а не NaN. Это может быть неожиданным поведением.

3. parseInt() и parseFloat() — для парсинга с игнорированием "мусора"

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

const mixed: string = "123abc";
const parsedInt: number = parseInt(mixed, 10); // 123 (второй аргумент — система счисления, всегда указывайте 10)
const parsedFloat: number = parseFloat("3.14xyz"); // 3.14

// Если строка начинается с нецифрового символа — возвращается NaN
const bad: string = "abc123";
console.log(parseInt(bad, 10)); // NaN

4. Number.parseInt() и Number.parseFloat() — современная альтернатива

В ES6 появились статические методы на объекте Number. Они полностью идентичны глобальным функциям, но считаются более "чистыми" с точки зрения стиля кода.

const value: string = "42px";
const pixels: number = Number.parseInt(value, 10); // 42

Какой метод выбрать? Практические рекомендации

  • Если строка гарантированно содержит только число (например, из JSON-парсинга) — используйте Number() или +. Они самые быстрые и явные.
  • Если строка может содержать дополнительные символы (например, "100px", "12.5em") — используйте parseInt() (для целых) или parseFloat() (для дробных).
  • Если нужна строгая валидация — комбинируйте Number() с проверкой через isNaN().

TypeScript-специфичные рекомендации

В TypeScript добавьте функцию-утилиту для безопасного преобразования:

function safeParseNumber(value: string): number | null {
  const num = Number(value);
  // Проверяем, что результат — конечное число (не NaN, не Infinity)
  if (isNaN(num) || !isFinite(num)) {
    return null; // или выбросить ошибку, или вернуть 0 — по ситуации
  }
  return num;
}

// Использование:
const input: string = "25.5";
const age = safeParseNumber(input);
if (age !== null) {
  console.log(age + 1); // 26.5
}

Производительность

По тестам производительности (на движке V8):

  • + и Number() — самые быстрые (разница минимальна)
  • parseInt() — немного медленнее, так как выполняет дополнительный парсинг
  • parseFloat() — аналогично parseInt

Однако в подавляющем большинстве приложений разница незаметна. Выбирайте по читаемости и надёжности, а не по скорости.

Итог: Для TypeScript нет какого-то "магического" метода. Используйте стандартные JavaScript-методы, но всегда добавляйте проверки на NaN и isFinite для надёжности. TypeScript только помогает контролировать типы на этапе компиляции, но не влияет на runtime-поведение.

<<>>

Альтернативный подход: использование TypeScript-дженериков и type guards

Если вы работаете с данными из ненадёжных источников (API, пользовательский ввод), рекомендую создать универсальную функцию-валидатор с использованием TypeScript type guards. Это сделает код более типобезопасным.

function isNumeric(value: unknown): value is number {
  return typeof value === 'number' && !isNaN(value) && isFinite(value);
}

function parseNumeric(input: string): number {
  const num = Number(input);
  if (!isNumeric(num)) {
    throw new Error(`Невозможно преобразовать "${input}" в число`);
  }
  return num;
}

// Использование с type narrowing
const rawValue: string = "42";
const parsedValue = parseNumeric(rawValue); // TypeScript знает, что это number

Обработка специальных случаев

Помните, что некоторые строки могут давать неожиданные результаты:

// Булевы значения
Number(true);  // 1
Number(false); // 0
// Но parseInt(true) вернёт NaN

// null и undefined
Number(null);      // 0
Number(undefined); // NaN

// Шестнадцатеричные строки
parseInt("0xFF"); // 255 (работает)
Number("0xFF");   // 255 (тоже работает)

Для максимальной безопасности используйте комбинацию: явное преобразование + проверка через isNaN() + обработка краевых случаев. TypeScript поможет вам не забыть про эти проверки на этапе компиляции.