当サイトは、アフィリエイト広告を利用しています

typescriptのスプレッド構文の使い方

作成日:2022月04月06日
更新日:2023年11月30日

スプレッド構文(Spread Syntax)

...hogeの形で下記配列やオブジェクトの要素を展開して扱うことができる構文。

配列で使う場合

スプレッド構文を使うことで新しい配列を作ったり、配列をマージしたり
分割したりすることができる。

sample.ts
// 配列を定義
const array1 = [1,2,3]
const array2 = [4,5,6,7]
// arrayを展開して新しい配列を作成
const newArray = [0,...array1,99]
console.log(newArray)
// array1とarray2を展開、マージする
const margeArray = [...array1,...array2]
console.log(margeArray)
// 分割代入とレスト構文で配列を分割する
const [val1,val2,...rest] = margeArray
console.log(val1,val2,rest)

オブジェクトで使う場合

オブジェクトで使う場合はプロパティの追加やオブジェクトのマージができる。
スプレッド構文は後に書いた方で上書きされるので注意が必要。

sample.ts
// 空オブジェクトの型
type EmptyObject = { [key: string]: any };
// オブジェクトを定義
const user:EmptyObject = { id: 1, name: "hogehoge" }
const userDetail:EmptyObject = { address: "xxx", weight:60 }
// 新規プロパティを追加する
const user2 = {...user,age:21}
console.log(user2)
// 結果
//{id: 1, name: "hogehoge", age: 21}
// オブジェクトをマージする
const margeUser = {...user,...userDetail}
console.log(margeUser)
// 結果
// {id: 1, name: "hogehoge", address: "xxx", weight: 60}
// 同じプロパティは上書きされる
let user3 = {...user2,age:99}
console.log(user3)
// 結果
// {id: 1, name: "hogehoge", age: 99}
// 順番を入れ替えてしますと設定した値も後ろに設定した値で
// 上書きされる
user3 = {age:99,...user2}
console.log(user3)
// 結果
// {age: 21, id: 1, name: "hogehoge"}

スプレッド構文はシャローコピー

スプレッド構文はシャローコピーなので
ネストしている配列やオブジェクトを扱う場合は注意する

sample.ts
// userタイプを定義
type User = {id:number, detail: {name:string, age:number}};
// オブジェクトを定義
const user:User = {id: 1, detail: {name: 'hoge', age: 29}};
// スプレッド構文でコピー(シャローコピー)
const copyUser = {...user}
// コピー元のnameを変更
user.detail.name = 'xxxxxxxxxx'
// コピーを出力
console.log(copyUser);
// ログ
// id: 1
// detail:{
// name: "xxxxxxxxxx"
// age: 29
// }

ネストされている場合は子はシャローコピーのためコピー元と同じ参照になってしまうため
コピー元のネスト部分を変更した場合、コピー先もかわってしまう。 ディープコピーしたい場合はスプレッド構文ではなく、下記の二つのどちらかでする

JSONメソッドを使う場合

JSONのstringifyとparseを使う

sample.ts
// userタイプを定義
type User = {id:number, detail: {name:string, age:number}};
// オブジェクトを定義
const user:User = {id: 1, detail: {name: 'hoge', age: 29}};
// JSONメソッドでコピー(ディープコピー)
const copyUser = JSON.parse(JSON.stringify(user))
// コピー元のnameを変更
user.detail.name = 'xxxxxxxxxx'
// コピーを出力
console.log(copyUser);
// ログ
// id: 1
// detail: {
// name: "hoge"
// age: 29
// }

コピー元が変わっても更新されていないが、注意としてはJSON.stringifyはオブジェクトを文字列に
変換してから再度、オブジェクトに戻すという手順を取っているため
文字列に変換できないundefinedや関数があった場合は情報が落ちる

JSONのstringifyとparseを使う(関数とundefinedがある場合)

sample.ts
// userタイプを定義
type User = {
id: number;
detail: { name: string; age?: number; func: (param: string) => string };
};
// 関数を定義
const func = (val: string) => `関数 : ${val}`;
// オブジェクトを定義
// ネストしたオブジェクトにundefinedと関数を設定する
const user: User = {
id: 1,
detail: { name: "hoge", age: undefined, func: func }
};
// JSONメソッドでコピー(ディープコピー)
const copyUser = JSON.parse(JSON.stringify(user));
// コピー元のnameを変更
user.detail.name = "xxxxxxxxxx";
// コピーを出力
console.log(copyUser);
// ログ
// id: 1
// detail: {
// name: "hoge"
// }

関数とundefinedであるプロパティはコピーできていない

lodashを使う

lodashのcloneDeepを使えばディープコピーをすることができる

sample.ts
import * as _ from "lodash";
// userタイプを定義
type User = {
id: number;
detail: { name: string; age?: number; func: (param: string) => string };
};
// 関数を定義
const func = (val: string) => `関数 : ${val}`;
// オブジェクトを定義
// ネストしたオブジェクトにundefinedと関数を設定する
const user: User = {
id: 1,
detail: { name: "hoge", age: undefined, func: func }
};
// lodashメソッドでコピー(ディープコピー)
const copyUser = _.cloneDeep(user);
// コピー元のnameを変更
user.detail.name = "xxxxxxxxxx";
// コピーを出力
console.log(copyUser);
// ログ
// id: 1
// detail: {
// name: "hoge"
// age: undefined
// func: ƒ func() {}
// }

関数とundefinedであるプロパティもコピーできている

参考

下記の記事を参考してまとめさせて頂きました。 JSのスプレッド構文を理解する
【JavaScript】スプレッド構文の便利な使い方まとめ

新着記事

タグ別一覧
top