【ITニュース解説】Paracetamol.ts💊| #45: Explica este código TypeScript
2025年09月08日に「Dev.to」が公開したITニュース「Paracetamol.ts💊| #45: Explica este código TypeScript」について初心者にもわかりやすく解説しています。
ITニュース概要
TypeScriptでは、`[25, "C"]`は要素の数や順序が自由な「配列」と推論される。一方、`[number, string]`は数・順序・型が固定された「タプル」である。この二つは異なる型のため、配列をタプルに代入できずエラーとなる。
ITニュース解説
プログラミング言語TypeScriptは、JavaScriptに「型」という概念を加えることで、コードの安全性と品質を高めることができる。この「型」を正しく理解することは、システムエンジニアとして成長する上で非常に重要である。今回は、似ているようで全く異なる二つの型、「配列」と「タプル」の違いに焦点を当て、なぜ特定のコードがエラーになるのかを深く掘り下げていく。
まず、問題となっているコードの最初の行 const temperatura = [25, "C"]; を見てみよう。これは、temperatura という名前の定数に、数値の 25 と文字列の "C" を要素として持つデータを代入している。JavaScriptの経験があれば、これは単なる配列だと感じるだろう。TypeScriptも一見すると同じように解釈するが、裏側では「型推論」という機能が働いている。型推論とは、開発者が明示的に型を指定しなくても、代入された値からTypeScriptが自動的に最適な型を推測してくれる便利な機能である。この場合、temperatura は数値と文字列という異なる型の要素を含んでいるため、TypeScriptはこれを「数値または文字列のどちらかの要素を、任意の数だけ持つことができる配列」と推論する。この型は、TypeScriptの記法で (number | string)[] と表現される。この | は「または」を意味するユニオン型を表し、[] は配列であることを示している。重要なのは、この型が「要素の数」や「各位置の要素の型」について何も保証していない点である。例えば、この型の変数には後から temperatura.push(100) や temperatura.push("Hello") のように要素を追加することが可能であり、要素数は2個に限定されない。
次に、二行目の const tupla:[number, string] = temperatura; を見てみよう。こちらは、tupla という定数を宣言し、それに temperatura を代入しようとしている。ここで注目すべきは、tupla のコロンの後に書かれている [number, string] という記述である。これは「型注釈」と呼ばれ、開発者が「この変数 tupla は、こういう型でなければならない」とTypeScriptに明確に指示するものである。この [number, string] という型は「タプル(Tuple)」と呼ばれる特殊な型である。タプルは、配列と似ているが、より厳格なルールを持つ。この型注釈は、「要素の数は厳密に2個でなければならず、かつ1番目の要素は number 型、2番目の要素は string 型でなければならない」という強い制約を意味している。配列のように要素を追加したり、順序を入れ替えたりすることは想定されていない、固定的なデータの組を表現するために使用される。
ここで問題が発生する。一行目で定義された temperatura の型は (number | string)[] であり、これは「要素数が可変で、順序も保証されない配列」であった。一方で、二行目で定義された tupla の型は [number, string] であり、これは「要素数が2個に固定され、型と順序も厳密に決まっているタプル」である。TypeScriptは、型の安全性を保つため、より制約の緩い型から、より制約の厳しい型への代入を原則として許可しない。なぜなら、もしこの代入が許されてしまうと、矛盾が生じる可能性があるからだ。例えば、temperatura はもともと配列なので、temperatura.push(30) のように3つ目の要素を追加することが文法上可能である。もし、その temperatura を tupla に代入できてしまうと、要素数が2個であるはずの tupla が、実際には3つの要素を持つことになり、タプル型の定義(制約)が破られてしまう。このような危険性を未然に防ぐため、TypeScriptのコンパイラは「型 (number | string)[] を型 [number, string] に割り当てることはできません」というエラーを出すのである。
では、このエラーを解消し、意図した通りに動作させるにはどうすればよいだろうか。問題の根源は、TypeScriptの型推論が temperatura を汎用的な配列型 (number | string)[] と解釈してしまったことにある。開発者の意図が「25度摂氏」という固定的なデータの組を表現することであったなら、最初の宣言の時点でその意図をTypeScriptに伝える必要がある。具体的には、temperatura を宣言する際に、tupla と同じように明示的な型注釈を与えることで解決できる。
const temperatura:[number, string] = [25, "C"];
このように記述すると、TypeScriptは temperatura をもはや汎用的な配列とは見なさず、「1番目の要素が数値、2番目の要素が文字列である、要素数2のタプル」として正確に認識する。この結果、temperatura の型は [number, string] となる。こうなれば、次に const tupla:[number, string] = temperatura; を実行する際には、[number, string] 型の値を、同じ [number, string] 型の変数に代入することになるため、何の問題もなく処理が成功する。
今回の事例は、TypeScriptにおける型システムの厳密さと、それがもたらす安全性について理解するための優れた教訓となる。型推論は非常に便利だが、常に開発者の意図を完璧に汲み取ってくれるわけではない。特に、配列リテラル [ ] を使って固定的なデータの組を定義しようとする場合、TypeScriptはデフォルトでそれをより柔軟な「配列」として推論しがちである。そのため、座標データ [x, y] や、今回の温度と単位 [25, "C"] のように、要素の数、型、順序に明確な意味があるデータを扱う場合は、明示的にタプル型 [number, number] や [number, string] を注釈することが、意図しないエラーを防ぎ、コードの堅牢性を高めるための重要なテクニックとなる。システムエンジニアを目指す上で、単にコードを書くだけでなく、そのコードがどのような「型」として解釈され、どのような制約を持つのかを意識する癖をつけることが、品質の高いソフトウェア開発への第一歩と言えるだろう。