TypeScriptで「参照渡し」を扱う方法をやさしく解説!

2024年11月29日金曜日

TypeScript

t f B! P L

TypeScriptで数値などのプリミティブ型の値を参照渡ししたことありますよね。でも、TypeScriptでは基本的に「値渡し」が使われるので、うまくいかないことも。

この記事では、TypeScriptで「参照渡し」のような動きを実現する方法を紹介していきます!

「値渡し」と「参照渡し」って?

まずは基本的な考え方からです。関数に値を渡す方法には、大きく分けて2つあります。

  • 値渡し
    値そのものをコピーして関数に渡します。関数内で変更しても元の値には影響しません。

  • 参照渡し
    値が入っている「場所」そのものを渡します。関数内で変更すると、元の値も変わります。

TypeScriptでは、数値や文字列などのシンプルな型(プリミティブ型)は値渡しオブジェクトや配列などは参照渡しのような動きをします。

オブジェクトを使って参照渡しを実現する

基本の例

まずは、オブジェクトを使った簡単な例を見てみましょう。

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

function updateUser(user: User): void {
  user.age += 1; // 年齢を1歳増やす
  user.name = user.name.toUpperCase(); // 名前を大文字にする
}

const user: User = { name: "Alice", age: 25 };
console.log("Before:", user);

updateUser(user);

console.log("After:", user);

実行結果

Before: { name: 'Alice', age: 25 }
After: { name: 'ALICE', age: 26 }

このように、関数内でオブジェクトを操作すると、元の値にも反映されます。これは、オブジェクトの「参照」が渡されているからです。

配列の場合も同じ!

配列も参照渡しのような動きをします。以下の例をご覧ください。

function addItem(arr: number[], item: number): void {
  arr.push(item); // 配列に新しい要素を追加
}

const numbers = [1, 2, 3];
console.log("Before:", numbers);

addItem(numbers, 4);

console.log("After:", numbers);

実行結果

Before: [1, 2, 3]
After: [1, 2, 3, 4]

関数の中でpushを使って配列を変更したら、元の配列にもその変更が反映されましたね。

プリミティブ型を参照渡しっぽく扱うには?

数値や文字列などのプリミティブ型は「値渡し」なので、そのままでは元の値を変更することができません。そんなときは、オブジェクトでラップする方法が便利です。

ラップして使う例

以下のように、数値をオブジェクトの中に入れて渡せばOKです!

type Wrapper = {
  value: number;
};

function increment(wrapper: Wrapper): void {
  wrapper.value += 1; // 値を増やす
}

const wrappedValue: Wrapper = { value: 10 };
console.log("Before:", wrappedValue);

increment(wrappedValue);

console.log("After:", wrappedValue);

実行結果

Before: { value: 10 }
After: { value: 11 }

これで、プリミティブ型でも参照渡しのような動きを実現できました!

注意したいこと

破壊的変更に注意

オブジェクトや配列を直接操作すると、意図しない副作用が起きることがあります。こういった場合は、一旦コピーを作成してから操作する方法もおすすめです。

コピーを作る例

スプレッド構文(...)を使ってコピーを作ると、元のデータを壊さずに操作できます。

function updateUserSafely(user: User): User {
  const updatedUser = { ...user }; // コピーを作る
  updatedUser.age += 1;
  return updatedUser;
}

const user: User = { name: "Alice", age: 25 };
const newUser = updateUserSafely(user);

console.log("Original:", user);
console.log("Updated:", newUser);

これで、元のデータを安心して使い回せます!

まとめ

TypeScriptでは、オブジェクトや配列を引数に渡すことで「参照渡し」のような動きが実現できます。また、プリミティブ型をオブジェクトでラップすることで、同様の挙動を模倣することも可能です。

ぜひ、試してみてください!

スポンサーリンク
スポンサーリンク

このブログを検索

Profile

自分の写真
Webアプリエンジニア。 日々新しい技術を追い求めてブログでアウトプットしています。
プロフィール画像は、猫村ゆゆこ様に書いてもらいました。

仕事募集もしていたり、していなかったり。

QooQ