はじめに
早くもTypeScript4件目となる記事です...
今回は配列についてまとめてみました。
【目次】
まずは基本的な型宣言をマスターしよう!
オブジェクト型の型宣言をマスターしよう!
関数の型定義をマスターしよう!
配列をマスターしよう! ←🈁
インターフェースをマスターしよう!
クラスを使いこなそう!
型修飾子についての理解を深めよう!
ジェネリックをマスターしよう!
独自の構文拡張をマスターしよう!
TypeScriptにおける配列
TypeScriptにおける配列のベストプラクティスとして、
「1つの配列につき、1つのデータ型」 という思考を尊重しています。
そのため既存の配列と異なる型のデータを挿入しようとすると 型エラー が発生します。
let strs = ["Hello", "World"]
// OK
strs.push("!")
// NG: Argument of type 'number' is not assignable to parameter of type 'string'.
strs.push(1234)
配列の型定義
配列の型定義は以下の形式で行います。
let 変数名: データ型[]
let strs: string[] = [];
let nums: number[] = [];
合併型の配列
「1つの配列につき、1つのデータ型」 というベストプラクティスは理解できましたが、異なるデータ型を1つの配列で扱いたいこともありますよね。
そのようなケースでは、合併型の配列を利用します。
let 変数名: (型A | 型B)[]
// string or number型のデータを格納する配列
let stringAndNumbers: (string | number)[] = [];
// OK
stringAndNumbers.push(1234);
stringAndNumbers.push("1234");
// NG: Argument of type 'boolean' is not assignable to parameter of type 'string | number'.
stringAndNumbers.push(true);
any型について
異なるデータ型を格納する配列の定義としてany[]
を利用することもできます。
しかし、any
型は間違った値の追加を許してしまう可能性があり、TypeScriptの恩恵を十分に受け取れません。
よほどのことがない限り利用しないようにしましょう。
let anyArray: any[] = []
タプル
タプルとは、固定サイズの配列です。
それぞれのインデックスにおいて、決まった型を持ちます。
以下の例において、TypeScritは以下の型定義を推論します。
-
tuple[0]
はnumber
型 -
tuple[1]
はstring
型
そのため、各データ型の固有メソッドが型の絞り込みなしに実行できます。
let tuple: [number, string]
tuple = [1234, "Hello"]
// OK
tuple[0].toFixed
// OK
tuple[1].toUpperCase
タプルへの値割当
タプル型は可変長引数よりも限定的な型です。
タプル型の変数に対して、可変長引数の割り当てはできません。
変数list
はTypeScriptによって(string | number)[]
型と型推論されています。
そのため、タプル型の[string, number]
に割り当てしようとするとエラーが発生します。
let list = ["str", 1234];
// NG: Type '(string | number)[]' is not assignable to type '[string, number]'
let tuple: [string, number] = list
// OK
let listSecond: [string, number] = ["str", 1234];
スプレッド引数とタプル
TypeScriptはスプレッド変数に対しても、正確な型チェックを行います。
変数args
は (string | number)[]
型と型推論されています。
関数fn
にスプレッド引数として渡されていますが、渡された引数はそれぞれ string | number
と推論されるため、型エラーが発生します。
function fn(input: string, num: number) {
console.log(input, num)
}
let args = ["inputText", 1234]
// NG: A spread argument must either have a tuple type or be passed to a rest parameter.
fn(...args);
これを改善するには、配列をタプル型として定義します。
こうすることで引数1がstring
、 引数2がnumber
型と推論され、型エラーが解消されます。
function fn(input: string, num: number) {
console.log(input, num)
}
let args:[string, number] = ["inputText", 1234]
// OK
fn(...args);
タプルの型推論
前述したように、TypeScriptはコード内で生成された配列を可変長引数としてみなします。
上記のようなケースでは、配列がタプル型であることを宣言する必要があります。
配列がタプル型であることを示すためのアプローチを2つご紹介します。
明示的なタプル型として定義
以下の関数fn
は戻り値としてタプル型を定義しています。
この変数の戻り値を、TypeScriptは[string, number]
のタプルであることを推論します。
よって、outputPair(...returnPair())
は型エラーが発生しません。
function returnPair(): [string, number] {
return ["CodeTaro", 24]
}
function outputPair(name: string, age: number) {
console.log(name, age)
}
// OK
outputPair(...returnPair());
constアサーション
値の末尾に as const
アサーションを定義することで、値が読み取り専用であることを推論します。
as const
アサーションを配列の末尾に付与することで、TypeScript はその配列をタプル型として扱うようになります。
function outputPair(name: string, age: number) {
console.log(name, age)
}
let pair = ["Taro", 24] as const;
// OK
outputPair(...pair);
const
アサーションを付与した変数に対して、値の更新を実行すると型エラーが発生しm
let pair = ["Taro", 24] as const;
// NG: Cannot assign to '0' because it is a read-only property.
pair[0] = "Tom"
まとめ
以上です!
思った以上に濃い内容となりました。
型推論は素晴らしい...
次節として、インターフェース に関する記事を公開しておりますので、よろしければご覧ください🙏