TypeScriptでは、アクセス修飾子はクラス内のプロパティおよびメソッドの可視範囲を制限するために使用されます:
class Animal { public name: string; private age: number; protected kind: string; constructor(name: string, age: number, kind: string) { this.name = name; this.age = age; this.kind = kind; } } class Dog extends Animal { bark() { console.log(this.kind); // OK: protected // console.log(this.age); // エラー: privateは子クラスで見えない } } const dog = new Dog('シャリク', 5, '哺乳類'); console.log(dog.name); // OK // console.log(dog.kind); // エラー: protected // console.log(dog.age); // エラー: private
#field が導入されましたが、これはすでにJSの仕様であり、異なる方法でコンパイルされます。質問: TypeScriptクラスのprivateプロパティに、JavaScriptにコンパイルされた後にアクセスできますか?
答え: はい、private(およびprotected)はコンパイル時のTypeScriptのチェックであり、ES5またはES6にコンパイルされた後はプライバシーが保持されず、プロパティはオブジェクトに残り、プロパティ名によるアクセスが可能です(例えば、object['privateProp']を通じて)。
// コンパイル後のJSコード function Animal(name, age, kind) { this.name = name; this.age = age; this.kind = kind; } var dog = new Animal('シャリク', 5, '哺乳類'); console.log(dog['age']); // 5 — TSレベルでのアクセス制限のみ!
物語
大規模なプロジェクトで、開発者はランタイムでのprivateフィールドのアクセス不可に頼っていました。その結果、オブジェクトをシリアライズ(JSON.stringify)してログに送信する際に、機密データが偶然に漏洩しました。なぜなら、TSの型チェックは実際のフィールドへのアクセスからは保護できなかったからです。
物語
プロジェクトでは、クラスのインスタンスを動的にプロパティを追加することで「拡張」するメカニズムが実装されました。動的に追加されたプロパティがprivate名を上書きし、そのために外部コードによって偶然に修正されてしまいました。エラーは生産環境でのみ発見され、プライバシーは確保されませんでした。
物語
JavaScriptからTypeScriptへの移行時に、チームはprotectedを使用することにしましたが、それが子クラス外からのフィールド利用を防ぐと思っていました。しかし、プログラマーは
Object.assignを通じて間違ってprotectedフィールドをランタイムで上書きし、デバッグの難しいバグを引き起こしました。これは、ランタイムのカプセル化がなかったため可能になりました。