TypeScriptでは、配列は主に2つの方法で記述されます: 型[] と Array<型>。異なる型の要素を持つ配列には、ユニオン型(union types)またはタプル(tuples)が使用され、異なる型と数の固定された要素のセットを記述できます。
配列の宣言:
let numbers: number[] = [1, 2, 3]; let strings: Array<string> = ['a', 'b', 'c'];
異なる型の要素を持つ配列:
let mixed: (string | number)[] = [1, 'a', 2];
タプル:
let tuple: [string, number, boolean] = ['hello', 42, true];
タプルは、固定された構造(例えば、関数から複数の異なる型の値を一度に返す場合)が期待されるときに便利で、配列は要素の数と型が混在しているか、事前に不明な場合に使用されます。
タプルの長さNを定義した後、pushを使用して要素を追加できますか?それは型付けにどのように影響しますか?
答え: はい、タプルにpushできます—コンパイラはこれを許可しますが、それはタプルの長さが制限されるという前提を破ります。新しい要素の型は、タプルのすべての可能な要素型のユニオンにキャストされます:
let tuple: [number, string] = [42, 'foo']; tuple.push(true); // OK! tupleは今: [number, string, boolean]ですが型は更新されず、エラーはありません! console.log(tuple); // [42, 'foo', true]
したがって、タプルの操作とその可変性は手動で管理するか、readonlyにする必要があります。
物語
開発者はタプル [number, string] を返す関数を記述しましたが、その後、結果に要素をpushすることを始めました。これにより、型が同期しなくなり、その後のコードは特定の型を持つちょうど2つの要素を期待していましたが、可変長の配列を受け取ることになり、値の展開や存在しないインデックスの読み取り時にランタイムエラーが発生しました。
物語
異なる型の値を格納するためにany[]配列が使用され、これは汎用的な解決策だと考えられました。その結果、TypeScriptは型の正確性をチェックしなくなり、アプリケーションのロジックが不正確な型変換のために「壊れ始め」、コンパイルエラーを引き起こさない状況が発生しました。
物語
プロジェクトで配列は型[]またはArray<型>で記述されましたが、ある場所ではlet arr: any[]と記述され(「何でも扱える」ため)、このため制御されない変換が発生しました。関数は任意の配列を受け入れるため、異なる型の要素に対して不正なメソッドを呼び出したときにランタイムでエラーが発生しました。