TL;DR:プライベート識別子を使用してプライベート フィールドを定義します。このようにして、アクセシビリティは実行時にも適用されます。
既に指摘したように、アクセシビリティは、TypeScript トランスパイラーによって (コンパイル時に) 静的にのみ適用されます。
したがって、パブリックまたはプライベートのすべてのプロパティは、通常の JavaScript プロパティとして発行されます。ここには魔法はありません。メソッドProxy
をトラップするためにa を使用するか、TypeScript の方法で宣言するのではなく使用する以外に、それらを非表示にすることはできません。後者のアイデアについては、次の例を考えました。ownKeys()
Object.defineProperties
class Foo {
constructor() {
Object.defineProperties(this, {
bar: {
enumerable: false,
value: "Hello world"
}
})
console.log((this as any).bar)
}
}
上記の例はTypeScript Playgroundでテストできます。
しかし、私はそのようなことをするのはアンチパターンだと思います。TypeScript の安全性をすべて壊してしまうからです。それが、単に JavaScript コードを書き出すのではなく、TypeScript を選択する唯一の理由です。
したがって、残された唯一の解決策は、プライベート識別子を使用することです。これは TypeScript の機能であり、名前が で始まるフィールド#
はコンパイル時だけでなく実行時にもプライベートとして適用されます。
class Foo {
#bar = "Hello world"
constructor() {
console.log(this.#bar)
}
}
console.log(Object.keys(new Foo()))
上記の例はTypeScript Playgroundでテストできます。
それはどのように機能しますか?トランスパイルされた JavaScript コードを見ただけで、突然WeakMap
. 実際、new への参照WeakMap
は、プライベート識別子を持つクラスのすべてのフィールドに対して、それらの宣言クラスが定義されているのと同じレキシカル スコープで定義されます。プライベート フィールドにアクセスする場合は常に、特定のマップ (そのフィールドを参照するときに渡される) を使用するゲッターまたはセッター関数を呼び出して、フィールドにアクセスするためのクラスのインスタンスである特定のキーで値を取得または設定します。の上。ゲッター関数とセッター関数の両方で実行時チェックも行われ、TypeError
登録されていないレシーバーで呼び出したときに a がスローされ、プライベート フィールドが異なる型のインスタンスでアクセスされたり、インスタンスがまったくアクセスされたりするのを防ぎます。