こんにちは。TypeScriptの世界へようこそ。
日々コードを書いていると、「このデータは外部から触らせたくないな」という場面に必ず遭遇しますよね。そんなとき、TypeScriptには複数の選択肢があり、初心者を悩ませがちです。
今日は、TypeScriptにおける「隠蔽(カプセル化)」の正体について、コンパイラの裏側を覗きながら一緒に紐解いていきましょう。ここを理解すれば、あなたの書くコードの「信頼性」が一段階上がりますよ。
—
1. そもそも「private修飾子」の正体とは?
TypeScriptの `private` キーワード。実はこれ、「コンパイル時にしか効かない魔法」なんです。
class User {
private secretKey: string = “SUPER_SECRET_123”;
public getSecret(): string {
return this.secretKey;
}
}
const user = new User();
// console.log(user.secretKey); // ❌ コンパイルエラー!
一見、「これでデータは守られた!」と感じますよね。しかし、TypeScriptをJavaScriptに変換(トランスパイル)した結果を見てみると……。
// コンパイル後のJS
var User = / @class / (function () {
function User() {
this.secretKey = “SUPER_SECRET_123”;
}
return User;
}());
驚きましたか? `secretKey` はただの平然としたプロパティとして残っていますよね。つまり、JavaScriptの実行環境(ブラウザやNode.js)から見れば、外部から普通にアクセスできてしまうのです。
TypeScriptの `private` は、「開発中にミスを防ぐためのガイドライン」であって、実行時のセキュリティを担保するものではありません。
—
2. #記号による「真のプライベート」の登場
そこで現代のJavaScript(ES2022以降)では、言語仕様として プライベートクラスフィールド(`#`) が導入されました。
class SecureUser {
#secretKey: string = “ACTUAL_SECRET_456”;
showSecret() {
console.log(this.#secretKey); // クラス内部からはアクセス可能
}
}
const secure = new SecureUser();
// console.log(secure.#secretKey); // ❌ TSコンパイルエラー!
// secure[“#secretKey”] // ❌ JS実行時もアクセス不能!
ここが重要なポイントです。`#` をつけると、JavaScriptエンジン自体がそのプロパティを「クラスの外からは絶対に触れない領域」として扱います。TypeScriptの型チェックをすり抜けて無理やりアクセスしようとしても、実行時にエラー(`SyntaxError` または `TypeError`)が発生します。
—
3. どっちを使うべき? 使い分けの極意
「じゃあ、全部 `#` にすればいいの?」という疑問が湧きますよね。ここがアーキテクトとしての腕の見せ所です。
`private` を使うべき場面
- 開発中の型安全性のみを重視する場合。
- コードベース全体でTypeScriptを使っており、コンパイルエラーで開発体験(DX)を向上させたい場合。
- JavaScriptへの変換サイズを小さく抑えたい場合(`#` は古い環境をサポートするために、変換時に複雑なロジックが付与されることがあります)。
`#` を使うべき場面
- 実行時の「真の隠蔽」が必要な場合。
- ライブラリを公開していて、利用者がどういうハックをしてくるか分からない場合。
- JavaScriptの仕様に準拠した、堅牢なクラス設計を行いたい場合。
—
4. 陥りやすい罠:「Interface」との関係
初心者がよく混乱するのが、「Interfaceでプライベートなプロパティを定義できますか?」という質問です。
結論から言うと、インターフェースは「公開インターフェース(API)」の定義に特化しているため、`private` や `#` を含めることはできません。
interface IUser {
// private name: string; // ❌ エラー!インターフェースは公開されるべきもの
name: string;
}
インターフェースは「外から見て、何ができるか」を定義する契約書です。一方で、`private` や `#` は「中身をどう守るか」という実装の詳細です。「契約(Interface)」と「実装(Class)」を分離して考えるのが、TypeScriptを掌握する最短ルートです。
—
最後に:型システムの重みを知る
TypeScriptの `private` は、いわば「開発者の良心」に寄り添う機能。そして `#` は「言語仕様としての鉄壁」です。
どちらが優れているかではなく、「誰がこのコードを触るのか」「どこまで厳密に隠蔽する必要があるのか」という文脈に合わせて選ぶことが、プロフェッショナルな設計というものです。
ここをクリアしたあなたは、もうクラス設計で迷うことはありません。自信を持って、堅牢なクラスを設計していってください。何か詰まったら、いつでもまた聞きに来てくださいね。応援しています!