タプルとは?
タプルとは、異なる型に要素をもつ固定長の配列のことです。
TypeScriptでは、特定の位置に特定の型の要素があることを保証するための
データ構造として使用されます。
配列との違いは、要素の型と個数が固定されている点になります。
タプルのいろいろ
タプルの基礎として、使い方や注意点を解説していきます。
宣言と初期化
タプルは、角括弧([])を使用して宣言します。
要素ごとに型を指定し、初期化の際は指定した型の順番に対応させる必要があります。
// 宣言
let person: [string, string, number];
// 初期化
person = ['tanaka', 'hiroshi', 45];
要素へのアクセス
次は作成したタプルへのアクセス方法を見ていきます。
配列へのアクセスと同様に角括弧でアクセスできます。
console.log(person[0]); // tanaka
console.log(person[1]); // hiroshi
console.log(person[2]); // 45
要素数の制約
タプルの注意点として、固定長のため宣言された要素数以上の要素を持つことは出来ません。
let numbers: [number, number] = [10, 20];
// let numbers: [number, number] = [10, 20, 30]; // これはエラーになる
可変長タプル型
TypeScript 4.0以降で追加された機能で、可変長のタプル型を定義できるようになりました。
少し難易度があがるので、今回は詳細は省きますが、
以下のように可変長の引数を受け取ることが可能です。
// 可変長のタプル型を引数として受け取り、最初の要素を取得する関数の型定義
type FirstElement<T extends unknown[]> = T extends [infer U, ...unknown[]] ? U : never;
// 可変長のタプル型を引数として受け取り、最初の要素を取得する関数
function getFirstElement<T extends unknown[]>(arr: T): FirstElement<T> | undefined {
return arr[0] as FirstElement<T> | undefined;
}
console.log(getFirstElement(['aaa', 50])); // aaa
console.log(getFirstElement([[10, 20], 50])); // [10, 20]
このように、可変長タプル型は少し難しいので今は飛ばしてもOKです!
サンプルコード
次は、実際に使えそうなサンプルコードを紹介します。
商品情報の管理
まずは、シンプルなものから紹介します。
以下は、商品の名前と値段と在庫を管理するタプルを作成してみます。
type Item = [string, number, boolean];
const item1: Item = ['apple', 120, true];
const item2: Item = ['banana', 150, false];
const displayItem = (item: Item): void => {
const [name, price, isStock] = item;
console.log(`商品名:${name}、値段:${price}、在庫:${isStock ? 'あり' : 'なし'}`);
}
displayItem(item1); // 商品名:apple、値段:120、在庫:あり
displayItem(item2); // 商品名:banana、値段:150、在庫:なし
このコードで、すごく便利なことがあります。
その前に、タプルを使う上でのデメリットは、引数が複数になった場合に、
どの引数が何なのか把握しづらくなる点です。
そのデメリットを、上記のコードの7行目で解決しています。
const [name, price, isStock] = item;
このように記述することで、プログラマーが設定した変数にタプルを入れることが出来るので、
他のプログラマーが修正や拡張をする際に、その変数が何なのか特定しやすくなります。
タプルの返却
次は、少し難易度をあげて、関数の戻り値にタプルを使用してみます。
これは意外と便利なので、覚えておくと役に立つと思います。
type OperationResult = [boolean, string];
function divide(x: number, y: number): OperationResult {
if (y === 0) {
return [false, "ゼロで割ることはできません"];
}
return [true, (x / y).toString()];
}
const result1: OperationResult = divide(10, 2);
const result2: OperationResult = divide(8, 0);
// 戻り値のタプルの1番目の要素で計算有無の判定
if (result1[0]) {
console.log("結果:", result1[1]);
} else {
console.error("エラー:", result1[1]);
}
// 戻り値のタプルの1番目の要素で計算有無の判定
if (result2[0]) {
console.log("結果:", result2[1]);
} else {
console.error("エラー:", result2[1]);
}
// 実行結果
// 5
// ゼロで割ることはできません
関数の戻り値として、タプルを返却することが出来るので、
上記のサンプルコードのように、わざわざinterfaceやtypeなどを使わなくても、
手軽に型を作成して返却することができます。
ただし、タプルの引数が増えていくにつれ、他のプログラマーには分かりづらいので、
「商品情報の管理」のサンプルコードのように、変数に入れておくのが、
良いかと思います。
タプルの可能性
タプルは、簡易的なデータ構造を表現することに長けています。
そのため、いろいろな場面で活躍が予想されます。
データベースの結果処理 | データベースから取得したレコードを管理 |
座標の表現 | x軸、y軸、z軸などの座標や緯度経度を管理 |
幅と高さ | 画面サイズごとに幅と高さを管理 |
複数言語 | 日本語や英語やフランス語などの言語データを管理 |
最後に
ここまで読んでいただきありがとうございます。
タプルは使い方次第で、かなり便利になると思います。
特に座標管理などの使い方は、実際に使用する場面があればどんどん使いたいですね!
ただし、デメリットもあるので注意して使いましょう。
コメント