JavaScriptでは、関数に引数を渡す際、オブジェクトを引数として渡すことができます。しかし、JavaScriptだけでは、そのオブジェクトがどんな形や情報を持っているべきかを定義できません。
そこで、TypeScriptを使うと、オブジェクトがどんな形を持つべきか、つまりどんな情報を持っているべきかを「インターフェース」等を用いて、明示的に定義することができるようになります。
この記事では以下の内容を分かりやすく説明するように心掛けています。ご参考になれば幸いです。
- TypeScriptでオブジェクトを関数の引数に渡す方法
- 基本的な使い方
- オブジェクトを直接渡す方法
- オブジェクトを直接渡して、新たなオブジェクトを作成する方法
- プロパティ省略記法を用いない場合
- プロパティ省略記法を用いた場合
- 分割代入を利用したオブジェクトの各プロパティの参照方法
- 「オブジェクト」や「配列」が入れ子構造になっているオブジェクトを関数の引数に渡す場合
- 分割代入を用いない場合
- 分割代入を用いた場合
- デフォルト引数を用いて、デフォルト値を設定する方法
TypeScriptでオブジェクトを関数の引数に渡す基本的な使い方
まず、基本的な使い方を説明します。以下のプログラムでは、オブジェクトを引数として関数に渡しています。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
let personInfo: Person = {
name: "Taro",
age: 30
};
function displayPersonInfo(person: Person): void {
console.log("Name: " + person.name);
console.log("Age: " + person.age);
}
displayPersonInfo(personInfo);
// ログ
// Name: Taro
// Age: 30
上記のプログラムでは、Person
というインターフェースを定義し、それをdisplayPersonInfo
関数の引数の型として利用しています。
これにより、displayPersonInfo
関数に渡されるオブジェクトがPerson
インターフェースに準拠していることを保証され、間違った形状のオブジェクトをdisplayPersonInfo
関数に渡すことを防ぐことができます。
また、Person
インターフェースに準拠しているpersonInfo
オブジェクトをdisplayPersonInfo
関数の引数に渡しています。
personInfo
オブジェクトはname
プロパティとage
プロパティを持っており、displayPersonInfo
関数の内部でconsole.log
関数を用いて、各プロパティの値を参照しています。
オブジェクトを関数の引数に直接渡す方法
以下のプログラムに示すように、関数の呼び出し時に、直接オブジェクトを渡すこともできます。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
function displayPersonInfo(person: Person) {
console.log("Name: " + person.name);
console.log("Age: " + person.age);
}
displayPersonInfo({ name: "Taro", age: 30 }); //直接オブジェクトを渡している
// ログ
// Name: Taro
// Age: 30
上記のプログラムでは、{ name: "Taro", age: 30 }
をdisplayPersonInfo
関数の引数に直接渡しています。
displayPersonInfo
関数は、Person
インターフェイスに準拠したオブジェクトを引数として受け付けます。なお、Person
インターフェイスはstring型のname
とnumber型のage
という2つのプロパティを持つことを規定しています。
この方法は、関数が引数として受け取るオブジェクトの形状(プロパティの名前やデータ型)が明確で、その関数を呼び出して、新たなオブジェクトを作成する場合に便利です。次に、新たなオブジェクトを作成しているプログラム例を説明します。
オブジェクトを直接渡して、新たなオブジェクトを作成する方法
以下のプログラムでは、関数を呼び出して、新たなオブジェクトを作成しています。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
interface Payload {
payload: Person;
}
function wrapInPayload(person: Person): Payload {
return { payload: person }; //新たなオブジェクトを作成している
}
const result: Payload = wrapInPayload({ name: "Taro", age: 30 });
console.log(result);
// ログ
// { payload: { name: 'Taro', age: 30 } }
このプログラムでは、wrapInPayload
関数はPerson
型のオブジェクトを引数に取り、そのオブジェクトをpayload
プロパティの値として持つ新しいオブジェクトを作成しています。この新しいオブジェクトはPayload
型であり、関数の戻り値の型として指定されています。
上記のプログラムでは、wrapInPayload
関数に{ name: "Taro", age: 30 }
というオブジェクトを渡しています。この関数は、引数として渡されたオブジェクトを元に、新しいPayload
型のオブジェクト{ payload: { name: 'Taro', age: 30 } }
を作成し、返します。その返り値は定数result
に格納されています。
プロパティ省略記法について
JavaScript(およびTypeScript)では、「オブジェクトのプロパティ名」と「その値の変数名」が同じ場合、そのプロパティの値を省略することができます。これはプロパティ省略記法(Property Shorthand)といいます。
以下のプログラムでは、関数の引数名がpayload
となっており、その引数名payload
を関数内部で、payload
プロパティの値にして返しています。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
interface Payload {
payload: Person;
}
function wrapInPayload(payload: Person): Payload {
return { payload }; // 「関数の引数名(payload)」と「プロパティの値(payload)」が同じの場合、このように記述できる
}
const result: Payload = wrapInPayload({ name: "Taro", age: 30 });
console.log(result);
// ログ
// { payload: { name: 'Taro', age: 30 } }
このように、プロパティ省略記法は、「関数の引数名(payload)」と「プロパティの値(payload)」が一致するときに有効で、そのような場合にコードをより簡潔に書くことができます。つまり、以下の2つのコードは同じ動作をします。
// 省略記法を用いない場合
function wrapInPayload(payload: Person): Payload {
return { payload: payload };
}
// 省略記法を用いた場合
function wrapInPayload(payload: Person): Payload {
return { payload };
}
プロパティ省略記法を用いることで、コードをより簡潔に書くことができます。ただし、これは可読性に影響を及ぼすこともあるので、適切な場面で使うことが重要です。
「プロパティ省略記法(Property Shorthand)」は「オブジェクトリテラルの省略記法」、「オブジェクトリテラルプロパティ値の省略記法」、「オブジェクトリテラルプロパティ名の省略記法」とも呼ばれています。この記法はJavaScript ES6(ECMAScript 2015)以降で導入されました。
分割代入を利用したオブジェクトの各プロパティの参照方法
JavaScript(およびTypeScript)には分割代入(Destructuring assignment)という便利な機能があります。
関数の引数に分割代入を利用すると、渡されたオブジェクトから特定のプロパティを取り出すことができます。
以下のプログラムは分割代入を利用したプログラム例です。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
function displayPersonInfo({ name }: Person): void {
console.log("Name: " + name);
}
let personInfo: Person = {
name: "Taro",
age: 30
};
displayPersonInfo(personInfo);
// ログ
// Name: Taro
上記のプログラムでは、Person
インターフェースに準拠しているpersonInfo
オブジェクトをdisplayPersonInfo
関数の引数に渡しています。
personInfo
オブジェクトはname
プロパティとage
プロパティを持っています。
displayPersonInfo
関数は、Person
インターフェイスに準拠したオブジェクトを引数として受け付けます。displayPersonInfo
関数では、分割代入を利用しており、関数定義時の引数を{ name }: Person
と書くことで、personInfo
オブジェクトからname
プロパティのみを直接取り出しています。
このように、分割代入でプロパティ名(上記のプログラムでは、name
)を指定すれば、プロパティに対応する値(Taro
)が引数name
に格納された状態で関数が実行されます。
なお、name
プロパティもage
プロパティも取り出す場合には、以下の様に記述します。
// オブジェクトの形状を定義
interface Person {
name: string;
age: number;
}
function displayPersonInfo({ name, age }: Person): void {
console.log("Name: " + name);
console.log("Age: " + age);
}
let personInfo: Person = {
name: "Taro",
age: 30
};
displayPersonInfo(personInfo);
// ログ
// Name: Taro
// Age: 30
「オブジェクト」や「配列」が入れ子構造になっているオブジェクトを関数の引数に渡す場合
「オブジェクト」や「配列」が入れ子構造になっているオブジェクトも関数の引数に渡すことができます。これにより、より複雑なデータ構造を関数に渡すことが可能になります。
分割代入を用いない場合
interface Pet {
type: string;
name: string;
}
interface Person {
name: { first: string, last: string };
age: number;
hobbies: string[];
pets: Pet[];
}
let personInfo: Person = {
name: { first: "Taro", last: "Yamada" },
age: 30,
hobbies: ["music", "traveling"],
pets: [{type: "dog", name: "Pochi"}, {type: "cat", name: "Tama"}]
};
function displayPersonInfo(person: Person): void {
console.log("Name: " + person.name.last + person.name.first);
console.log("Age: " + person.age);
console.log("Hobbies:");
for(let hobby of person.hobbies){
console.log(" - " + hobby);
}
console.log("Pets:");
for(let pet of person.pets){
console.log(" - " + pet.type + ": " + pet.name);
}
}
displayPersonInfo(personInfo);
// ログ
// Name: YamadaTaro
// Age: 30
// Hobbies:
// - music
// - traveling
// Pets:
// - dog: Pochi
// - cat: Tama
分割代入を用いる場合
分割代入を用いると、以下のように記述することができます。
interface Pet {
type: string;
name: string;
}
interface Person {
name: { first: string, last: string };
age: number;
hobbies: string[];
pets: Pet[];
}
let personInfo: Person = {
name: { first: "Taro", last: "Yamada" },
age: 30,
hobbies: ["music", "traveling"],
pets: [{ type: "dog", name: "Pochi" }, { type: "cat", name: "Tama" }]
};
function displayPersonInfo({ name: { first, last }, age, hobbies, pets }: Person) {
console.log("Name: " + last + first);
console.log("Age: " + age);
console.log("Hobbies:");
for (let hobby of hobbies) {
console.log(" - " + hobby);
}
console.log("Pets:");
for (let pet of pets) {
console.log(" - " + pet.type + ": " + pet.name);
}
}
displayPersonInfo(personInfo);
// ログ
// Name: YamadaTaro
// Age: 30
// Hobbies:
// - music
// - traveling
// Pets:
// - dog: Pochi
// - cat: Tama
デフォルト引数を用いて、デフォルト値を設定する方法
JavaScript(およびTypeScript)の関数では、デフォルト引数と呼ばれる機能を用いることができます。
デフォルト引数を設定すると、関数実行時に引数が渡されなかった場合や、一部のプロパティしか持たないオブジェクトが渡された場合、関数はデフォルト値(初期値)を使って正常に実行されます。
// オブジェクトの形状を定義
interface Person {
name?: string;
age?: number;
}
function displayPersonInfo({ name = "No name", age = 0 }: Person = {}) {
console.log("Name: " + name);
console.log("Age: " + age);
}
// オブジェクトを引数に渡さない場合
displayPersonInfo();
// ログ
// Name: No name
// Age: 0
// 一部のプロパティを持つオブジェクトを引数に渡す場合
displayPersonInfo({ name: "Taro"});
// ログ
// Name: Taro
// Age: 0
上記のプログラムでは、displayPersonInfo
関数はデフォルト値を設定した2つのプロパティ(name
、age
)を持つオブジェクトを引数として受け取っています。
デフォルト値を設定しない場合、「undefined
」となります。
// オブジェクトの形状を定義
interface Person {
name?: string;
age?: number;
}
function displayPersonInfo({ name, age }: Person = {}) {
console.log("Name: " + name);
console.log("Age: " + age);
}
// オブジェクトを引数に渡さない場合
displayPersonInfo();
// ログ
// Name: No name
// Age: 0
// 一部のプロパティを持つオブジェクトを引数に渡す場合
displayPersonInfo({ name: "Taro" });
// ログ
// Name: Taro
// Age: 0
本記事のまとめ
この記事ではTypeScriptで『オブジェクトを関数の引数に渡す方法』について、以下の内容を説明しました。
- TypeScriptでオブジェクトを関数の引数に渡す方法
- 基本的な使い方
- オブジェクトを直接渡す方法
- オブジェクトを直接渡して、新たなオブジェクトを作成する方法
- プロパティ省略記法を用いない場合
- プロパティ省略記法を用いた場合
- 分割代入を利用したオブジェクトの各プロパティの参照方法
- 「オブジェクト」や「配列」が入れ子構造になっているオブジェクトを関数の引数に渡す場合
- 分割代入を用いない場合
- 分割代入を用いた場合
- デフォルト引数を用いて、デフォルト値を設定する方法
お読み頂きありがとうございました。