Array.prototype.sort()が数値を文字列として並べ替える理由
比較関数を渡さないsort()は、number[]という型が付いていても要素を文字列に変換してUnicodeコードポイント順に並べ替えます。数値の大小とは無関係な結果になります。
なぜエラーが出ないのか
出力: [ 10, 25, 40, 5 ]
(エラーなし)- TypeScriptは何も報告しません。型検査も構文も正しいためです
出力: [ 10, 25, 40, 5 ]- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 const nums: number[] = [10, 5, 40, 25]; 2 nums.sort( ); ^ 3 console.log(nums);
比較関数を渡さないsort()は要素を文字列として比較します。"10"は"5"より辞書順で小さいため、数値としては逆転した順序になります。
直し方: (空) を (a, b) => a - b にします。
パターン2
1 const scores: number[] = [9, 80, 700, 6]; 2 scores.sort( ); ^ 3 console.log(scores);
既定のsort()は文字列比較のため、"700"は"80"より前に来ます。数値順にしたい場合は比較関数が必須です。
直し方: (空) を (a, b) => a - b にします。
パターン3
1 const ids: number[] = [100, 21, 3]; 2 ids.sort( ); ^ 3 console.log(ids);
"100"、"21"、"3"を文字列として比較すると先頭の文字("1" < "2" < "3")で決まるため、この順のまま並びます。
直し方: (空) を (a, b) => a - b にします。
パターン4
1 const nums: number[] = [3, 20, 1]; 2 nums.sort( ); ^ 3 console.log(nums);
比較関数を渡さないsort()は要素を文字列として比較するため、数値順にはなりません。
直し方: (空) を (a, b) => a - b にします。
パターン5
1 const vals: number[] = [50, 7, 600]; 2 vals.sort( ); ^ 3 console.log(vals);
既定のsort()は文字列比較のため、"600"は"7"より前に来ます。
直し方: (空) を (a, b) => a - b にします。
よくある誤解
「number[]型なのだから、sort()は数の大小で並べ替えてくれるはず」という考えは誤りです。sort()の既定の比較は要素の型を問わず文字列化して行われるため、型を付けても挙動は変わりません。
実務での勘所
この不具合は、tsconfig.jsonの設定をどれだけ厳しくしても型チェックでは検出できません。sort()の型定義は比較関数を省略可能な引数として宣言しているため、比較関数を渡さない呼び出しは型としてまったく正当です。「数値の配列なのに比較関数が無い」という組み合わせ自体を、型システムは異常とみなす手段を持っていません。型チェックが万能ではなく、あくまで宣言された型の整合性だけを見る仕組みだと分かる、分かりやすい実例です。