【TypeScript】JSの暗黙の型変換に頼っていた文字列の数値変換はどう書くのか
前置き
例によってJSからTSに書き換える作業中の出来事を抽出。
javascript - 0
とかjavascript minus zero
とかjavascript 明示的 型変換
とか幾つか調べたけど直接的な答えはヒットしなかった。JavaScript畑の人たちには当たり前の事実なんだろうか。教えてほしい。
概要
JavaSciptで文字列を数値に変換する方法は幾つか存在するが、比較的よく使われるイディオムに下記のものがある。
const a = "1" - 0; console.log(a, typeof a); // 1, "number"
これを、TypeScriptではどう記述するのか?という問題。
const a = "1" - 0; // Compile error!!
つまり、正確に言えばTypeScript関係ない。でもJavaScriptを書くときに、結構意識しない気がするんだよねコレ。暗黙の変換を使用して問題になることの方が少ないだろうし。
少なくとも詳細な動きまでは私は意識したことない。そもそも個人的にnullとかundefinedや数値変換できないような文字列とかに対してやりたくないんだよね。無駄に確認項目増えそうで。
回答
殆どのケースではNumber()
が同じ動きになる。
殆どのケースというか、多分これで正しいのだけど、正確な答えは正直わからなかった。。。英語ムズカシイ
const obj = { valueOf: function() { return 123; } } console.log(obj.valueOf()); // 123 console.log(obj - 0); // 123 // 文字列 -> 数値変換の場合はvalueOf()の戻り値が使われる。文末の参考リンクを参照 console.log(Number(obj)); // 123 console.log(parseFloat(obj)); // 123 obj++; // ちなみにincrementもできる console.log(obj); // 124
メモ
「文字列 - 数値」を計算する際に、文字列は数値へ暗黙の型変換が行われる。
そのロジックはECMAScriptの仕様書のここあたりに記載されている。
Number()へのリンクとかが貼られていれば確証が持てるのだけど、パース手順みたいなのが書いてあるんだよねBNF的な。
時間あるときにちゃんと読むかな。正直そんな時間あるならこんなこと意識しなくて済むような記述にすれば良いと思う。折角TypeScriptなんだし。回避できる言語仕様は回避した方が脳のリソースを無駄にしなくて良いし!というと言い訳になるか。
補足
new Number()
とNumber()
は違う。前者はラッパーオブジェクトを作成するし、後者はプリミティブオブジェクトを生成する。MDNの例が詳しい。parseFloat()
ではダメ。parseFloat(null)
とnull - 0
とNumber(null)
の結果でわかる。
参考
- https://qiita.com/uhyo/items/44c2f79873de13186743
- http://ecma-international.org/ecma-262/6.0/index.html#sec-tonumber
- https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number
雑感
// @ts-ignore
で逃げるNumber()
を信じる …どうしたものか。確実に動きが変わらないのは前者なんだけどね。
追記(2020-03-06)
なんて思ってたら、「+」のイディオムは使えるようですよ(´・ω・`) bigintでは使えないようですが、十分な気はする。
let aaa = "123"; console.log(typeof aaa); // string console.log(typeof +aaa); // number aaa = null; console.log(typeof aaa); // object console.log(typeof +aaa); // number console.log(+aaa); // 0 console.log(Number(aaa)); // 0 aaa = 123n; console.log(typeof aaa); // console.log(typeof +aaa); // Uncaught TypeError: Cannot convert a BigInt value to a number // console.log(+aaa); // Uncaught TypeError: Cannot convert a BigInt value to a number console.log(Number(aaa));
参考URL:
https://qiita.com/uhyo/items/cc92a553059274d85403#%E5%8D%98%E9%A0%85%E6%BC%94%E7%AE%97%E5%AD%90