diff --git a/packages/documentation/copy/en/handbook-v2/Classes.md b/packages/documentation/copy/en/handbook-v2/Classes.md index 3b06a145eee3..be5b9e9e2804 100644 --- a/packages/documentation/copy/en/handbook-v2/Classes.md +++ b/packages/documentation/copy/en/handbook-v2/Classes.md @@ -256,24 +256,24 @@ Since [TypeScript 4.3](https://devblogs.microsoft.com/typescript/announcing-type ```ts twoslash class Thing { - _size = 0; + _size = 0; - get size(): number { - return this._size; - } - - set size(value: string | number | boolean) { - let num = Number(value); + get size(): number { + return this._size; + } - // Don't allow NaN, Infinity, etc + set size(value: string | number | boolean) { + let num = Number(value); - if (!Number.isFinite(num)) { - this._size = 0; - return; - } + // Don't allow NaN, Infinity, etc - this._size = num; + if (!Number.isFinite(num)) { + this._size = 0; + return; } + + this._size = num; + } } ``` @@ -725,7 +725,8 @@ class A { #### Caveats -Like other aspects of TypeScript's type system, `private` and `protected` are only enforced during type checking. +Like other aspects of TypeScript's type system, `private` and `protected` [are only enforced during type checking](https://www.typescriptlang.org/play?removeComments=true&target=99&ts=4.3.4#code/PTAEGMBsEMGddAEQPYHNQBMCmVoCcsEAHPASwDdoAXLUAM1K0gwQFdZSA7dAKWkoDK4MkSoByBAGJQJLAwAeAWABQIUH0HDSoiTLKUaoUggAW+DHorUsAOlABJcQlhUy4KpACeoLJzrI8cCwMGxU1ABVPIiwhESpMZEJQTmR4lxFQaQxWMm4IZABbIlIYKlJkTlDlXHgkNFAAbxVQTIAjfABrAEEC5FZOeIBeUAAGAG5mmSw8WAroSFIqb2GAIjMiIk8VieVJ8Ar01ncAgAoASkaAXxVr3dUwGoQAYWpMHBgCYn1rekZmNg4eUi0Vi2icoBWJCsNBWoA6WE8AHcAiEwmBgTEtDovtDaMZQLM6PEoQZbA5wSk0q5SO4vD4-AEghZoJwLGYEIRwNBoqAzFRwCZCFUIlFMXECdSiAhId8YZgclx0PsiiVqOVOAAaUAFLAsxWgKiC35MFigfC0FKgSAVVDTSyk+W5dB4fplHVVR6gF7xJrKFotEk-HXIRE9PoDUDDcaTAPTWaceaLZYQlmoPBbHYx-KcQ7HPDnK43FQqfY5+IMDDISPJLCIuqoc47UsuUCofAME3Vzi1r3URvF5QV5A2STtPDdXqunZDgDaYlHnTDrrEAF0dm28B3mDZg6HJwN1+2-hg57ulwNV2NQGoZbjYfNrYiENBwEFaojFiZQK08C-4fFKTVCozWfTgfFgLkeT5AUqiAA). + This means that JavaScript runtime constructs like `in` or simple property lookup can still access a `private` or `protected` member: ```ts twoslash @@ -741,7 +742,59 @@ const s = new MySafe(); console.log(s.secretKey); ``` -If you need to protect values in your class from malicious actors, you should use mechanisms that offer hard runtime privacy, such as closures, weak maps, or [private fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields). +`private` also allows access using bracket notation during type checking. This makes `private`-declared fields potentially easier to access for things like unit tests, with the drawback that these fields are _soft private_ and don't strictly enforce privacy. + +```ts twoslash +// @errors: 2341 +class MySafe { + private secretKey = 12345; +} + +const s = new MySafe(); + +// Not allowed during type checking +console.log(s.secretKey); + +// OK +console.log(s["secretKey"]); +``` + +Unlike TypeScripts's `private`, JavaScript's [private fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields) (`#`) remain private after compilation and do not provide the previously mentioned escape hatches like bracket notation access, making them _hard private_. + +```ts twoslash +class Dog { + #barkAmount = 0; + personality = "happy"; + + constructor() {} +} +``` + +```ts twoslash +// @target: esnext +// @showEmit +class Dog { + #barkAmount = 0; + personality = "happy"; + + constructor() {} +} +``` + +When compiling to ES2021 or less, TypeScript will use WeakMaps in place of `#`. + +```ts twoslash +// @target: es2015 +// @showEmit +class Dog { + #barkAmount = 0; + personality = "happy"; + + constructor() {} +} +``` + +If you need to protect values in your class from malicious actors, you should use mechanisms that offer hard runtime privacy, such as closures, WeakMaps, or private fields. Note that these added privacy checks during runtime could affect performance. ## Static Members