©️
Typescript シャローコピー・ディープコピー
TypescriptのObject.is
でシャローコピーとディープコピーについて理解したので学習したことをまとめます。
Object.is(arg1, arg2)
引数で受け取った2つのオブジェクトを比較し、一致するかを判定します。
この比較は参照レベルで行われます。
type OriginObj = {
name: string;
age: number;
contact: {
email: string;
phone?: string;
};
};
const originObj: OriginObj = {
name: "田中太郎",
age: 30,
contact: {
email: "tanaka@example.com",
phone: "090-1234-5678",
},
};
const ref = originObj;
Object.is(originObj, ref) // true
シャローコピー
浅いコピーともいわれます。const shallow = {...obj}
のように、スプレッド構文でコピーするとシャローコピーになります。
このコピーは、オブジェクトの第一階層まではコピーされますが、第二階層(オブジェクトの中にさらにオブジェクトがある場合)は参照が渡されます。
つまり、第二階層以降はコピーではなく、元と同じもの(参照レベルで)。
type OriginObj = {
name: string;
age: number;
contact: {
email: string;
phone?: string;
};
};
const originObj: OriginObj = {
name: "田中太郎",
age: 30,
contact: {
email: "tanaka@example.com",
phone: "090-1234-5678",
},
};
const shallowObj = { ...originObj };
console.log(shallowObj);
// 出力
// 見かけ上は同じ
// {
// name: "田中太郎",
// age: 30,
// contact: {
// email: "tanaka@example.com",
// phone: "090-1234-5678",
// }
// }
// この比較はfalse
Object.is(originObj, shallowObj);
// この比較はtrue
Object.is(originObj.contact, shallowObj.contact);
ディープコピー
シャローコピーとは異なり、すべての階層のコピーを取る。
JSON.parce + JSON.stringify
で実現できるが、これだと型がanyになってしまいます。
type OriginObj = {
name: string;
age: number;
contact: {
email: string;
phone?: string;
};
};
const originObj: OriginObj = {
name: "田中太郎",
age: 30,
contact: {
email: "tanaka@example.com",
phone: "090-1234-5678",
},
};
const deepObj = JSON.parse(JSON.stringify(originObj));
console.log(deepObj);
// 出力
// 見かけ上は当然同じ
// {
// name: "田中太郎",
// age: 30,
// contact: {
// email: "tanaka@example.com",
// phone: "090-1234-5678",
// }
// }
// この比較はfalse
Object.is(originObj, deepObj);
// この比較もfalse
Object.is(originObj.contact, deepObj.contact);
// anyなので存在しないプロパティにアクセスしてもエラーにならない!
deepObj.hontohanai;
structuredClone
anyを回避する方法として、structuredClone
があります。
type OriginObj = {
name: string;
age: number;
contact: {
email: string;
phone?: string;
};
};
const originObj: OriginObj = {
name: "田中太郎",
age: 30,
contact: {
email: "tanaka@example.com",
phone: "090-1234-5678",
},
};
const deepObj = structuredClone(originObj);
// この比較はfalse
Object.is(originObj, deepObj);
// この比較もfalse
Object.is(originObj.contact, deepObj.contact);
// エラーになる!
deepObj.hontohanai;
ただしこれも万能というわけではなく、関数や独自クラスのインスタンス、Symbolはコピーできません。lodash
というライブラリを使うことでも解決できるらしいですが、今回は触れません。
Discussion