【入門編】引数の型に「読み取り専用(Readonly)」を強制する設計パターン – TypeScript コア・型システムの基礎解析バイブル

こんにちは。TypeScriptの世界へようこそ。

TypeScriptの型システムは、単なる「エラーを防ぐための道具」ではありません。それは、「あなたのコードがどのように振る舞うべきか」という設計図を、コンパイラという最強のパートナーと共有するための言語です。

今日は、多くの開発者が何気なく使い、しかしその本質を見落としがちな「読み取り専用(Readonly)」の強制について深掘りしていきましょう。これを知るだけで、あなたの書く関数の信頼性は劇的に向上します。

—

なぜ、関数の中で「破壊」が起きてはいけないのか

プログラミングの現場で最も恐ろしいバグの一つは、「意図しない副作用」です。関数にオブジェクトを渡したつもりが、その関数の中で中身を書き換えられてしまい、呼び出し元のデータまで変わってしまう……。

function updateScore(user: { score: number }) {
// 悪気はないが、元のオブジェクトを書き換えてしまっている
user.score += 10;
}

const player = { score: 0 };
updateScore(player);
console.log(player.score); // 10 になってしまった!

これ、小さいプログラムなら良いですが、巨大なアプリケーションでは「どこでデータが変わったのか」を追跡するだけで数時間を溶かすことになります。これを防ぐのが `Readonly` という型安全の守護神です。

—

Readonlyで「不変(Immutable)」を強制する

TypeScriptには、オブジェクトのプロパティを「読み取り専用」にする魔法があります。引数の型に `Readonly` を使うだけで、その関数内ではオブジェクトの書き換えが一切禁止されます。

実践:Readonlyを用いた防御的プログラミング

interface User {
name: string;
score: number;
}

// Readonly を使って「この関数は中身をいじらないよ!」と宣言する
function printUser(user: Readonly) {
console.log(`User: ${user.name}, Score: ${user.score}`);

// もしここで書き換えようとすると…?
// user.score = 100; // エラー: Cannot assign to ‘score’ because it is a read-only property.
}

このコードを見てください。コンパイラが「おっと、そこは書き換えてはいけない場所だぞ」と即座に教えてくれます。これがTypeScriptの強みです。実行する前に、ミスを論理的に排除する。 これがプロの仕事です。

—

よくある落とし穴:Readonlyの「深さ」に注意

初心者が陥りやすい罠が、「Readonlyは浅い」という点です。例えば、オブジェクトの中にさらにオブジェクトがある場合、外側を `Readonly` にしても内側までは保護されません。

interface State {
config: { theme: string };
}

function processState(state: Readonly) {
// これはエラーになる(保護されている)
// state.config = { theme: ‘dark’ };

// しかし、これはエラーにならない!
state.config.theme = ‘dark’; // 危険!副作用が発生する
}

これを防ぐには、TypeScript 3.4以降で導入された `const` アサーションや、再帰的に読み取り専用にする `DeepReadonly` 型を自作する必要があります。実務では、`Readonly` を使う際は「このオブジェクトはフラットか?」を意識することが大切ですね。

—

なぜこの設計パターンが「最強」なのか

私がこのパターンを強く推奨する理由は、「関数のインターフェースを見るだけで、その関数の安全性がわかるから」です。

1. 型を見るだけで、副作用がないと確信できる。
2. コンパイラがガードしてくれるので、安心して他のコードに集中できる。
3. 将来の自分がコードを修正する際、うっかり書き換えても怒られるので安全。

コードは「書く」ことよりも「読み返される」時間の方が圧倒的に長いものです。未来の自分やチームメンバーに対して、「このデータは壊さないから安心して使ってね」と型でメッセージを残す。これが、TypeScriptを掌握するエンジニアの姿勢です。

—

まとめ:あなたのコードを「不変」に守ろう

最後に、今回のポイントをまとめます。

  • `Readonly` は、意図しない副作用を防ぐ防波堤。
  • 「書き換えない」という意思を型で表明する。
  • ただし、ネストされたオブジェクトの「深さ」には注意を払う。

ここをクリアすれば、あなたの書くコードは一気にプロフェッショナルな品質に近づきます。型システムをただの「制約」と捉えるのではなく、「安全に速く走るためのガードレール」だと思って、ぜひ積極的に `Readonly` を使ってみてください。

何か分からないことがあれば、いつでも聞いてくださいね。TypeScriptの道は奥が深いですが、一歩ずつ進めば必ず景色が変わりますよ。応援しています!

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