分割代入引数 (destructuring assignment parameter)
JavaScriptでは分割代入構文は関数の引数でも使えます。引数がオブジェクトや配列の場合、そのオブジェクトや配列の一部だけを関数で利用したい場合に、分割代入引数が便利です。
分割代入引数の構文
JavaScriptでは、オブジェクトの分割代入引数の構文は中カッコ中に、オブジェクトのプロパティ名を書きます。引数名はプロパティ名と一致する必要があります。
js
functionfoo ({a ,b }) {console .log (a ,b );}foo ({a : 1,b : 2,c : 3 });
js
functionfoo ({a ,b }) {console .log (a ,b );}foo ({a : 1,b : 2,c : 3 });
プロパティ名を別の引数名で受け取るには、:
の後に引数名を指定します。
js
functionfoo ({a :x ,b :y }) {console .log (x ,y );}foo ({a : 1,b : 2 });
js
functionfoo ({a :x ,b :y }) {console .log (x ,y );}foo ({a : 1,b : 2 });
配列の分割代入引数は、カギカッコの中に配列要素を代入する変数名を書きます。配列要素に対応する引数名は自由に決められます。
js
functionbar ([a ,b ]) {console .log (a ,b );}bar ([1, 2, 3]);
js
functionbar ([a ,b ]) {console .log (a ,b );}bar ([1, 2, 3]);
分割代入引数はアロー関数でも使えます。
js
constfoo = ({a ,b }) => {};constbar = ([a ,b ]) => {};
js
constfoo = ({a ,b }) => {};constbar = ([a ,b ]) => {};
分割代入引数の型注釈
TypeScriptでオブジェクトを分割代入する場合、分割代入引数の右にオブジェクトの型注釈を書きます。
ts
functionfoo ({a ,b }: {a : number;b : number }) {}// ^^^^^^^^^^^^^^^^^^^^^^^^^^型注釈
ts
functionfoo ({a ,b }: {a : number;b : number }) {}// ^^^^^^^^^^^^^^^^^^^^^^^^^^型注釈
配列を分割代入する場合も、分割代入引数の右に配列型の型注釈を書きます。
ts
functionbar ([num1 ]: number[]) {}
ts
functionbar ([num1 ]: number[]) {}
型注釈が配列型の場合、コンパイラオプションnoUncheckedIndexedAccess
を有効にした場合、分割代入引数はundefined
とのユニオン型になります。
ts
functionbar ([num1 ]: number[]) {}
ts
functionbar ([num1 ]: number[]) {}
📄️ noUncheckedIndexedAccess
インデックス型のプロパティや配列要素を参照したときundefinedのチェックを必須にする
配列の分割代入引数の型注釈をタプル型にすると、noUncheckedIndexedAccess
が有効な場合でも、undefined
とのユニオン型にはなりません。
ts
functionbar ([num1 ,num2 ]: [number, number]) {}
ts
functionbar ([num1 ,num2 ]: [number, number]) {}
既定値とコンパイルエラー
JavaScriptでは、分割代入引数に対応するオブジェクトプロパティや配列要素が無い場合、undefined
が代入されます。
js
functionfoo ({a }) {console .log (a );}functionbar ([a ]) {console .log (a );}foo ({});bar ([]);
js
functionfoo ({a }) {console .log (a );}functionbar ([a ]) {console .log (a );}foo ({});bar ([]);
一方、TypeScriptでは分割代入引数に対応するオブジェクトプロパティや配列要素が無いと、コンパイルエラーになります。
ts
functionfoo ({a }: {a : number }) {}functionbar ([a ]: [number]) {}Argument of type '{}' is not assignable to parameter of type '{ a: number; }'. Property 'a' is missing in type '{}' but required in type '{ a: number; }'.2345Argument of type '{}' is not assignable to parameter of type '{ a: number; }'. Property 'a' is missing in type '{}' but required in type '{ a: number; }'.foo ({} );Argument of type '[]' is not assignable to parameter of type '[number]'. Source has 0 element(s) but target requires 1.2345Argument of type '[]' is not assignable to parameter of type '[number]'. Source has 0 element(s) but target requires 1.bar ([] );
ts
functionfoo ({a }: {a : number }) {}functionbar ([a ]: [number]) {}Argument of type '{}' is not assignable to parameter of type '{ a: number; }'. Property 'a' is missing in type '{}' but required in type '{ a: number; }'.2345Argument of type '{}' is not assignable to parameter of type '{ a: number; }'. Property 'a' is missing in type '{}' but required in type '{ a: number; }'.foo ({} );Argument of type '[]' is not assignable to parameter of type '[number]'. Source has 0 element(s) but target requires 1.2345Argument of type '[]' is not assignable to parameter of type '[number]'. Source has 0 element(s) but target requires 1.bar ([] );
分割代入引数のデフォルト引数
JavaScriptで分割代入引数のデフォルト引数を指定する場合、引数名の後に=
と既定値を書きます。
js
functionfoo ({a = 0 }) {// ^^^既定値の指定console .log (a );}functionbar ([a = 0]) {// ^^^既定値の指定console .log (a );}foo ({});bar ([]);
js
functionfoo ({a = 0 }) {// ^^^既定値の指定console .log (a );}functionbar ([a = 0]) {// ^^^既定値の指定console .log (a );}foo ({});bar ([]);
TypeScriptでデフォルト引数を型注釈する場合、オブジェクトではプロパティを?
でオプションにします。
ts
functionfoo ({a = 0 }: {a ?: number | string }) {}
ts
functionfoo ({a = 0 }: {a ?: number | string }) {}
プロパティの既定値からプロパティの型が予想できる場合、型注釈を省略できる場合もあります。
ts
functionfoo ({a = 0 }) {}
ts
functionfoo ({a = 0 }) {}
分割代入引数の全体の既定値
分割代入引数の全体の既定値を指定する場合、分割代入構文の後に=
と既定値を書きます。この既定値は、引数全体が無い、または、undefined
の場合に採用されます。
js
functionfoo ({a ,b } = {a : 0,b : 0 }) {console .log (a ,b );}foo ();foo ({a : 1 });functionbar ([a ,b ] = [0, 0]) {console .log (a ,b );}bar ();bar ([1]);
js
functionfoo ({a ,b } = {a : 0,b : 0 }) {console .log (a ,b );}foo ();foo ({a : 1 });functionbar ([a ,b ] = [0, 0]) {console .log (a ,b );}bar ();bar ([1]);
TypeScriptでは、引数全体の既定値は型注釈の後に書きます。
ts
// ................型注釈の位置functionfoo ({a }: {a ?: number } = {a : 0 }) {}// ^^^^^^^^^^既定値の位置
ts
// ................型注釈の位置functionfoo ({a }: {a ?: number } = {a : 0 }) {}// ^^^^^^^^^^既定値の位置
各プロパティの既定値と引数全体の既定値の両方を指定することもできます。この場合、引数全体を省略すると、各プロパティの既定値が使われます。
ts
typeObj = {a ?: number;b ?: number };functionfoo ({a = 0,b = 0 }:Obj = {}) {console .log (a +b );}foo ();foo ({});foo ({a : 1 });foo ({a : 1,b : 2 });
ts
typeObj = {a ?: number;b ?: number };functionfoo ({a = 0,b = 0 }:Obj = {}) {console .log (a +b );}foo ();foo ({});foo ({a : 1 });foo ({a : 1,b : 2 });
呼び出し時のプロパティ名の省略
JavaScriptでは、分割代入引数の引数名と同じ変数が定義済みであれば、オブジェクトリテラルのプロパティ名を省略し、変数だけ渡すことができます。
ts
functionbmi ({height ,weight }: {height : number;weight : number }) {}// プロパティ名と同じ変数constheight = 170;constweight = 65;// プロパティ名を省略しない呼び出しbmi ({height :height ,weight :weight });// プロパティ名を省略した呼び出しbmi ({weight ,height });
ts
functionbmi ({height ,weight }: {height : number;weight : number }) {}// プロパティ名と同じ変数constheight = 170;constweight = 65;// プロパティ名を省略しない呼び出しbmi ({height :height ,weight :weight });// プロパティ名を省略した呼び出しbmi ({weight ,height });
📄️ Shorthand property names
オブジェクトのキーと変数名が同じ時にかぎり、オブジェクトに値を代入するときも同様にShorthand property namesを使うことができます。これも分割代入と調べると情報を得られることがあります。次の例がほぼすべてです。
学びをシェアする
・分割代入引数は関数でobjectや配列を部分的に使うときに便利
・objectは中カッコで引数を書く
→ function foo({ a, b })
・配列はカギカッコで引数を書く
→ function foo([a, b])
・型注釈は分割代入の後に書く
・既定値も指定可
→ function foo({ a = 0})
『サバイバルTypeScript』より
関連情報
📄️ オブジェクトの分割代入
JavaScriptには、オブジェクトの分割代入(destructuring assignment)という便利な構文があります。分割代入は、オブジェクトからプロパティを取り出す機能です。
📄️ 配列の分割代入
配列の分割代入