TypeScript オブジェクト配列 定義方法
TypeScriptでオブジェクトの配列を定義する方法
TypeScriptでは、オブジェクトの配列を定義するための2つの主な方法があります。
型アノテーションを使用する
// 型アノテーションを使用してオブジェクトの配列を定義
interface Person {
name: string;
age: number;
}
const people: Person[] = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];
- **Person[]**のように、配列の要素の型を指定します。
- interfaceを使用して、オブジェクトの構造を定義します。
ジェネリック型を使用する
// ジェネリック型を使用してオブジェクトの配列を定義
const people2: Array<{ name: string; age: number }> = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];
- Array<T>のようなジェネリック型を使用し、配列の要素の型を指定します。
どちらの方法でも、オブジェクトの構造が一致している限り、配列にオブジェクトを追加することができます。
例
people.push({ name: "Charlie", age: 20 });
注意
- オブジェクトの構造が複雑な場合は、より明確な型定義を使用することをおすすめします。
- TypeScriptは静的型付け言語なので、配列に定義されていない型のオブジェクトを追加しようとするとエラーが発生します。
interface Person {
name: string;
age: number;
}
const people: Person[] = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];
解説
- [{ name: "Alice", age: 30 }, { name: "Bob", age: 25 }]
people
配列に、Person
インターフェースで定義された構造を持つ2つのオブジェクトを初期値として代入しています。
- const people: Person[]
people
という名前の定数を定義し、その型をPerson[]
と指定しています。Person[]
は、Person
型のオブジェクトを要素とする配列を表します。
- interface Person
Person
という名前のインターフェースを定義しています。- このインターフェースは、
name
という文字列のプロパティと、age
という数値のプロパティを持つオブジェクトの構造を定義しています。
このコードの意味
- 各要素は、
Person
インターフェースで定義された構造に従ったオブジェクトになります。 people
という変数に、name
とage
というプロパティを持つ人の情報を格納する配列を定義しています。
const people2: Array<{ name: string; age: number }> = [
{ name: "Alice", age: 30 },
{ name: "Bob", age: 25 },
];
- const people2: Array<{ name: string; age: number }>
people2
という名前の定数を定義し、その型をArray<{ name: string; age: number }>
と指定しています。Array<T>
は、任意の型T
を要素とする配列を表すジェネリック型です。- ここでは、
T
として{ name: string; age: number }
というオブジェクト型を指定しています。
- 1つ目の方法と比べて、インターフェースを定義せずに直接配列の要素の型を指定しています。
どちらの方法でも、TypeScriptはpeople
やpeople2
に格納できるオブジェクトの構造を厳密にチェックします。そのため、誤った型のオブジェクトを配列に追加しようとした場合、コンパイルエラーが発生します。
どちらの方法を選ぶべきか
- ジェネリック型を使う場合
- 簡単なオブジェクトの配列を定義したい場合
- インターフェースを定義するのが冗長だと感じる場合
- インターフェースを使う場合
- オブジェクトの構造を明確に定義したい場合
- 複数の場所で同じ構造のオブジェクトを使う場合
- 配列の要素の型は、より複雑なオブジェクトやユニオン型、インターセクション型など、様々な型を指定することができます。
- TypeScriptでは、
interface
の代わりにtype
エイリアスを使うこともできます。
// ユニオン型
const mixedArray: Array<string | number> = ["hello", 42];
// インターセクション型
interface Person {
name: string;
}
interface Address {
city: string;
}
type PersonWithAddress = Person & Address;
const peopleWithAddress: PersonWithAddress[] = [];
型アノテーションとインターフェース
これまで見てきたように、インターフェースを用いた型アノテーションは、オブジェクトの構造を明確に定義し、型安全性を高める上で非常に有効です。
より柔軟な定義
- インデックスシグネチャ
動的なプロパティを持つオブジェクトを定義できます。interface Person { [key: string]: any; // 任意の文字列のプロパティを持つ }
- 読み取り専用プロパティ
プロパティの値を変更できないようにします。interface Person { readonly id: number; // idは読み取り専用 }
- オプションプロパティ
すべてのオブジェクトに必ずしも存在しないプロパティを定義できます。interface Person { name: string; age?: number; // ageはオプション }
型エイリアス
インターフェースの代わりに、型エイリアスを使ってオブジェクトの型を定義することもできます。
type Person = {
name: string;
age: number;
};
インターフェースと型エイリアスは、多くの場合、同じように使用できますが、微妙な違いがあります。詳細については、TypeScriptのドキュメントを参照してください。
ジェネリック型
ジェネリック型は、再利用可能な型を定義する際に非常に便利です。
function createArray<T>(items: T[]): T[] {
return [...items];
}
const numberArray = createArray<number>([1, 2, 3]);
const personArray = createArray<Person>([{ name: 'Alice', age: 30 }]);
クラス
オブジェクトの構造を定義する際に、クラスを使うこともできます。
class Person {
constructor(public name: string, public age: number) {}
}
const people: Person[] = [
new Person('Alice', 30),
new Person('Bob', 25),
];
Mapped Type
既存の型から新しい型を生成できます。
interface User {
name: string;
age: number;
isAdmin: boolean;
}
type ReadonlyUser = Readonly<User>; // 全てのプロパティが読み取り専用
Utility Types
TypeScriptには、Partial
, Pick
, Omit
などのユーティリティ型が用意されており、既存の型から新しい型を簡単に作成できます。
type PartialPerson = Partial<Person>; // 全てのプロパティがオプション
TypeScriptでは、オブジェクトの配列を定義する方法は多岐にわたります。どの方法を選ぶかは、オブジェクトの構造の複雑さ、コードの可読性、再利用性などを考慮して決定します。
選択のポイント
- オブジェクト指向
クラス - 再利用可能な型
ジェネリック型 - 柔軟な構造
インデックスシグネチャ、Mapped Type - シンプルで静的なオブジェクト
インターフェースまたは型エイリアス
重要なポイント
- クラス
オブジェクト指向プログラミングの概念を取り入れることができます。 - ジェネリック型
再利用可能なコードを書く上で非常に重要です。 - インターフェースと型エイリアス
どちらもオブジェクトの型を定義しますが、微妙な違いがあります。 - 型アノテーション
TypeScriptの最大の強みです。型を明示的に指定することで、コンパイル時にエラーを発見し、コードの品質を向上させることができます。
typescript