TypeScriptで文字列を数値に変換するには Number(text) を呼びます。結果の型は number で、テキストが正しい数値でなければ NaN になります。"42px" のように後ろに文字が続くテキストには parseInt(text, 10) か parseFloat(text) を使います。
4つの変換はどれも number 型を返します。TypeScriptはテキストが正しかったかどうかを知りません。不正な文字列でも number が返り、その値が NaN になるだけです。
変換が必要な理由
フォームの入力、URLのパラメーター、環境変数、ファイルの内容は文字列として届きます。TypeScriptは、数値が期待される場所で文字列を使うことを許しません:
index.ts(3,23): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type.
文字列に対する -、*、/ の計算はエラーです。+ は許されますが連結になるので、"3" + 10 は文字列 "310" になります。だからこそ先に変換が必要です: Number(quantity) * 10。
型アサーションも役に立ちません。quantity as number は拒否され(TS2352)、as unknown as number で無理に通してもコンパイラーを黙らせるだけで、実行時の値は文字列のままです。
Number、parseInt、parseFloat、単項プラスの違い
4つの関数はきれいな入力では同じ結果になり、それ以外ではすべて食い違います。次の表は、Node でそれぞれを実行した実際の出力です:
| 入力 | Number(s) | +s | parseInt(s, 10) | parseFloat(s) |
|---|---|---|---|---|
"42" | 42 | 42 | 42 | 42 |
"3.99" | 3.99 | 3.99 | 3 | 3.99 |
"42px" | NaN | NaN | 42 | 42 |
"" | 0 | 0 | NaN | NaN |
" 3 " | 3 | 3 | 3 | 3 |
"1e3" | 1000 | 1000 | 1 | 1000 |
"0x1F" | 31 | 31 | 0 | 0 |
"1,000" | NaN | NaN | 1 | 1 |
"12_000" | NaN | NaN | 12 | 12 |
"abc" | NaN | NaN | NaN | NaN |
表の背景にあるルール:
Numberと単項+はまったく同じです。前後の空白を取り除いたうえで文字列全体を変換し、1e3や0xの16進数を理解し、何か残ればNaNを返します。空文字列や空白だけの文字列は0になります。parseIntとparseFloatは先頭から読み、使えない文字が出たところで止まるので、"42px"や"1,000"は途中までの数値になります。空文字列はNaNです。parseIntは小数部を切り捨て、指数表記を理解しません:"1e3"はeで止まります。- 数値の区切り文字(
12_000)はソースコードでは有効ですが、文字列の中では使えません。
入力の検証には、より厳密な Number が向いています。parseInt と parseFloat は、CSSのサイズのように単位や接尾辞が本当に付いているテキストに向いています。
不正な入力の扱い: NaN
NaN の型は number なので、コンパイラーは警告を出しません。結果は自分で Number.isNaN か Number.isFinite でチェックします:
戻り値を number | undefined にすると失敗が型の一部になり、呼び出し側は計算の前に必ずそれを処理することになります。Number.isFinite は Infinity も弾きます。Number("Infinity") は平然と Infinity を返すからです。
グローバルの isNaN(x) は避けてください。引数を先に変換するので、JavaScriptでは isNaN("abc") が true になります。TypeScriptの宣言は number しか受け付けないので、文字列を渡すとエラー TS2345 になります。これは、変換済みの値に Number.isNaN を使えというヒントです。
文字列を整数に変換する
parseInt には必ず2番目の引数である基数を渡してください。10進数のテキストなら 10 です。省略もできますが、意図が明確になり、ほかの基数では重要になります。小数の文字列から整数を得るには、変換してから明示的に丸めます。
parseInt は文字列を受け取るので、parseInt(12.7) はコンパイルエラー(TS2345)になります。これは役に立つエラーです。JavaScriptの parseInt は数値を先にテキストに変換するため、0.0000005 のような値では間違った答え(5)を返すからです。数値には Math.trunc を使います。Number.MAX_SAFE_INTEGER を超える整数は、BigInt(text) なら値全体を解析できます(不正なテキストでは NaN を返す代わりに SyntaxError を投げます)。
数値を文字列に変換する
String(n)、n.toString()、`${n}` のどれでも、数値をいちばん短い文字列の形に変換できます。書式を細かく決めるにはフォーマット用のメソッドを使います:
toFixed は入力した10進数ではなく2進数の値を丸めるので、(1.005).toFixed(2) は "1.00" になります。1.005 は1.005よりわずかに小さい値として保持されているからです。金額は整数のセント単位で持つか、Intl.NumberFormat でフォーマットしてください。
String(n) は null や undefined にも使えます(結果は "null" と "undefined")。一方 n.toString() は、値がないかもしれないため strict のもとではコンパイルエラーになります。
早見表
| やりたいこと | コード | 結果の型 |
|---|---|---|
| 文字列を数値に(厳密) | Number(s) または +s | number(NaN の可能性あり) |
| テキスト先頭の整数を取り出す | parseInt(s, 10) | number(NaN の可能性あり) |
| テキスト先頭の小数を取り出す | parseFloat(s) | number(NaN の可能性あり) |
| 結果をチェックする | Number.isFinite(n), Number.isNaN(n) | boolean |
| 大きな整数 | BigInt(s) | bigint |
| 数値を文字列に | String(n), n.toString(), `${n}` | string |
| 小数点以下の桁数を固定 | n.toFixed(2) | string |
| ほかの基数 | n.toString(16) | string |
| 桁区切り | n.toLocaleString("en-US") | string |
よくある質問
TypeScriptで文字列を数値に変換するには?
Number(text) を使います。戻り値は number で、数値として正しいテキストならその値、それ以外は NaN、空文字列や空白だけの文字列なら 0 になります。"42px" のように後ろに文字が続くことがあるテキストには parseInt(text, 10) か parseFloat(text) を使います。
as number で文字列を数値にキャストできますか?
as number で文字列を数値にキャストできますか?できません。"42" as number はコンパイルエラー(TS2352)で、unknown を経由して無理に通しても、型アサーションが変えるのはコンパイラーから見た型だけです。実行時の値は文字列 "42" のままです。値は Number()、parseInt()、parseFloat() で変換してください。
TypeScriptの Number() と parseInt() の違いは?
Number は文字列全体を変換し、一部でも数値でなければ NaN を返すので、Number("42px") は NaN です。parseInt は先頭から数字を読んで最初の数字以外の文字で止まるので、parseInt("42px", 10) は 42 になり、小数部は切り捨てます。Number("") は 0 ですが、parseInt("") は NaN です。
文字列が正しい数値かどうかを判定するには?
変換してから結果を調べます: const n = Number(text); if (text.trim() !== "" && Number.isFinite(n)) { ... }。Number("") は 0 になるので、空文字列のチェックが必要です。グローバルの isNaN ではなく Number.isNaN を使ってください。TypeScriptではグローバルの isNaN は number 引数しか受け付けません。
TypeScriptで数値を文字列に変換するには?
String(n)、n.toString()、テンプレートリテラル `${n}` はどれも同じ結果になります。小数点以下の桁数を固定するなら n.toFixed(2)、ほかの基数なら n.toString(16)、桁区切りなら n.toLocaleString("en-US") を使います。