TypeScript | 基礎文法:オブジェクト基礎 – オブジェクトの再代入

TypeScript
スポンサーリンク

「オブジェクトの再代入」とは何を指しているのか

まず言葉の整理からいきます。
ここでいう「オブジェクトの再代入」は、変数に入っているオブジェクトそのものを、別のオブジェクトに入れ替えることを指します。

type User = {
  name: string;
  age: number;
};

let user: User = {
  name: "Taro",
  age: 20,
};

user = {
  name: "Hanako",
  age: 18,
}; // ← これが「再代入」
TypeScript

一方で、

user.name = "Jiro"; // これは「プロパティの書き換え」
TypeScript

これは「再代入」ではなく、「同じオブジェクトの中身を変えている」だけです。
この2つを頭の中でちゃんと分けておくと、let / const / readonly の意味が一気にクリアになります。


let と const と「オブジェクトの再代入」

let の場合:オブジェクトの再代入も中身の変更もOK

type User = {
  name: string;
  age: number;
};

let user: User = {
  name: "Taro",
  age: 20,
};

user.name = "Jiro"; // OK(プロパティの変更)

user = {
  name: "Hanako",
  age: 18,
}; // OK(オブジェクトごと入れ替え)
TypeScript

let で宣言した変数は、「変数に入っている参照そのものを入れ替えてよい」ので、
オブジェクトの再代入も自由にできます。

const の場合:再代入はNGだが、中身の変更はOK

const user: User = {
  name: "Taro",
  age: 20,
};

user.name = "Jiro"; // OK(中身の変更)

// user = { name: "Hanako", age: 18 }; // エラー:再代入はできない
TypeScript

ここが最初に一番混乱しやすいポイントです。

const は「変数に入っている“参照”を変えられない」だけであって、
「オブジェクトの中身が不変になる」という意味ではありません。

  • user = ... のように、別のオブジェクトを丸ごと代入し直すのは NG
  • user.name = ... のように、同じオブジェクトのプロパティを書き換えるのは OK

この違いを、意識的に見分けられるようになると、const の挙動がスッと腑に落ちます。


型と再代入:「同じ型のオブジェクト」しか入れ替えられない

型が合わないオブジェクトは再代入できない

type User = {
  name: string;
  age: number;
};

let user: User = {
  name: "Taro",
  age: 20,
};

user = {
  name: "Hanako",
  age: 18,
}; // OK

user = {
  name: "Ken",
  // age がない
}; // エラー:Property 'age' is missing
TypeScript

変数 user の型は User なので、
「再代入するときも、User 型のオブジェクトでなければならない」というルールが常に効いています。

つまり、再代入は「変数の中身を入れ替える」だけでなく、
「型の契約を守っているかどうかを再チェックされるタイミング」でもあります。


readonly と再代入:「変えられない」のはどこか

readonly プロパティは「中身の変更」が禁止される

type User = {
  readonly id: number;
  name: string;
};

let user: User = {
  id: 1,
  name: "Taro",
};

user.name = "Jiro"; // OK
// user.id = 2;     // エラー:id は readonly
TypeScript

readonly は「プロパティの書き換え」を禁止しますが、
変数自体の再代入は別の話です。

user = {
  id: 2,
  name: "Hanako",
}; // これはOK(user 変数に別の User を入れ直しているだけ)
TypeScript

ここで起きているのは、

  • user.id = 2 → 「同じオブジェクトの id を変えようとしている」ので NG
  • user = { id: 2, ... } → 「変数 user に別のオブジェクトを入れている」ので OK

という違いです。

変数自体を「再代入不可」にしたいなら const

const user: User = {
  id: 1,
  name: "Taro",
};

// user = { id: 2, name: "Hanako" }; // エラー:const なので再代入不可
TypeScript
  • 「プロパティを書き換えたくない」→ readonly
  • 「変数に別のオブジェクトを入れ直したくない」→ const

この2つは、守っている対象が違います。
「どこを固定したいのか?」を意識して、readonlyconst を使い分けるのが大事です。


オブジェクトの再代入と「参照の共有」

同じオブジェクトを複数の変数が指している場合

type User = {
  name: string;
};

let a: User = { name: "Taro" };
let b = a;

b.name = "Jiro";

console.log(a.name); // "Jiro"
TypeScript

ここでは、ab同じオブジェクトを参照しています。
b.name を変えると、a.name も変わって見えるのはそのためです。

一方で、再代入すると「どの変数がどのオブジェクトを指しているか」が変わります。

let c: User = { name: "Taro" };
let d = c;

d = { name: "Hanako" };

console.log(c.name); // "Taro"
console.log(d.name); // "Hanako"
TypeScript

ここでは、

  • 最初は cd が同じオブジェクトを指していた
  • d = { ... } で、d だけ別のオブジェクトを指すようになった

という状態です。

「プロパティの変更」と「再代入」は、参照の共有の観点でもまったく違う動きになる
この感覚を持っておくと、バグの原因を追いやすくなります。


初心者がまず掴んでおきたい「オブジェクトの再代入」の感覚

押さえておきたいポイントを、あえてシンプルにまとめるとこうです。

  • 「再代入」は、変数が指しているオブジェクトそのものを入れ替えること
  • let は再代入OK、const は再代入NG(でも中身の変更はOK)
  • 型は「再代入のたびに」チェックされるので、常にその型の契約を守る必要がある
  • readonly は「プロパティの書き換え」を禁止するが、「変数への再代入」とは別物
  • 同じオブジェクトを複数の変数が参照しているとき、「プロパティ変更」と「再代入」で挙動が大きく変わる

「今自分がやっているのは、オブジェクトの“中身”を変えているのか?
それとも、変数が指している“オブジェクトそのもの”を入れ替えているのか?」

この問いを、コードを書くときに一瞬だけでも意識できるようになると、
let / const / readonly / 型チェックの意味が、かなりクリアに見えてきます。

タイトルとURLをコピーしました