Skip to content

update classes caveat documentation with more info on # private fields #1903

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 6, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 68 additions & 15 deletions packages/documentation/copy/en/handbook-v2/Classes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
```

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down