private
TypeScript 3.8 以降では、キーワードを使用してメンバーをプライベートにマークする場合と、キーワードを使用してメンバーをプライベートにマークする場合の違いは何ですか。
class PrivateKeywordClass {
private value = 1;
}
そして#
プライベートフィールドを使うJavaScript 用に提案:
class PrivateFieldClass {
#value = 1;
}
どちらか一方を優先すべきでしょうか?
ベストアンサー1
プライベートキーワード
のプライベートキーワードTypeScriptではコンパイル時アノテーション。これは、プロパティがそのクラス内でのみアクセス可能であることをコンパイラに伝えます。
class PrivateKeywordClass {
private value = 1;
}
const obj = new PrivateKeywordClass();
obj.value // compiler error: Property 'value' is private and only accessible within class 'PrivateKeywordClass'.
ただし、コンパイル時のチェックは、たとえば型情報をキャストすることで簡単にバイパスできます。
const obj = new PrivateKeywordClass();
(obj as any).value // no compile error
このprivate
キーワードは実行時にも強制されません。
発行されたJavaScript
TypeScript を JavaScript にコンパイルする場合、private
キーワードは単純に削除されます。
class PrivateKeywordClass {
private value = 1;
}
次のように変わります:
class PrivateKeywordClass {
constructor() {
this.value = 1;
}
}
private
このことから、キーワードがランタイム保護を提供しない理由がわかります。生成された JavaScript では、これは単なる通常の JavaScript プロパティです。
プライベートフィールド
プライベートフィールド財産が秘密に保たれていることを保証する実行時:
class PrivateFieldClass {
#value = 1;
getValue() { return this.#value; }
}
const obj = new PrivateFieldClass();
// You can't access '#value' outside of class like this
obj.value === undefined // This is not the field you are looking for.
obj.getValue() === 1 // But the class itself can access the private field!
// Meanwhile, using a private field outside a class is a runtime syntax error:
obj.#value
// While trying to access the private fields of another class is
// a runtime type error:
class Other {
#value;
getValue(obj) {
return obj.#value // TypeError: Read of private field #value from an object which did not contain the field
}
}
new Other().getValue(new PrivateKeywordClass());
TypeScript では、クラス外でプライベート フィールドを使用しようとすると、コンパイル時エラーも出力されます。
プライベートフィールドは、TC-39 ECMAScript 提案これらは 2021 ECMAScript 仕様の一部であり、通常の JavaScript と TypeScript の両方で使用できることを意味します。
発行されたJavaScript
TypeScriptでプライベートフィールドを使用し、出力にES2021またはそれ以前のバージョンのJavaScriptをターゲットにしている場合、TypeScriptは以下を使用してプライベートフィールドの実行時の動作をエミュレートするコードを生成します。WeakMap
(ソース)。
class PrivateFieldClass {
constructor() {
_x.set(this, 1);
}
}
_x = new WeakMap();
ES2021 以降をターゲットにしている場合、TypeScript はプライベート フィールドを出力します。
class PrivateFieldClass {
constructor() {
this.#x = 1;
}
#x;
}
どれを使えばいいでしょうか?
それは何を達成しようとしているかによります。
キーワードprivate
は適切なデフォルトです。設計された目的を達成し、TypeScript 開発者によって長年使用されてきました。既存のコードベースがある場合は、プライベート フィールドを使用するためにすべてのコードを切り替える必要はありません。これは、 をターゲットにしていない場合特に当てはまります。TS がesnext
プライベート フィールドに対して生成する JS がパフォーマンスに影響を与える可能性があるためです。また、プライベート フィールドには、キーワード とは微妙ですが重要な違いがあることにも留意してくださいprivate
。
ただし、実行時のプライバシーを強制する必要がある場合、またはesnext
JavaScript を出力する場合は、プライベート フィールドを使用する必要があります。
また、JavaScript/TypeScript エコシステム内でプライベート フィールドが普及するにつれて、どちらか一方を使用する組織/コミュニティの慣例も進化することにも留意してください。
その他の注目すべき相違点
プライベートフィールドは、
Object.getOwnPropertyNames
および同様のメソッドによって返されません。プライベートフィールドはシリアル化されません
JSON.stringify
継承には重要なエッジケースがある
たとえば、TypeScript では、スーパークラスのプライベート プロパティと同じ名前のプライベート プロパティをサブクラスで宣言することは禁止されています。
class Base { private value = 1; } class Sub extends Base { private value = 2; // Compile error: }
これはプライベート フィールドでは当てはまりません。
class Base { #value = 1; } class Sub extends Base { #value = 2; // Not an error }
初期化子のないキーワード プライベートプロパティ
private
では、出力される JavaScript でプロパティ宣言は生成されません。class PrivateKeywordClass { private value?: string; getValue() { return this.value; } }
コンパイル結果:
class PrivateKeywordClass { getValue() { return this.value; } }
一方、プライベート フィールドは常にプロパティ宣言を生成します。
class PrivateKeywordClass { #value?: string; getValue() { return this.#value; } }
コンパイル結果 ( をターゲットとする場合
esnext
):class PrivateKeywordClass { #value; getValue() { return this.#value; } }