ECMAScript Private Fields
Introduction
Private fields called also private names it's a new feature of ECMAScript specification that at this moment is in Stage 3. As feature name suggests, it allows us to have private fields inside of ECMAScript classes.
We can use class fields in most modern JavaScript runtimes i.e. Node 12, the latest versions of Chrome, and Firefox, TS 3.8.
In this note, I'll focus on the usage with TypeScript.
Syntax
1class Foo {2 bar = 'bar'3 #baz = 'baz' // private class field4}56class Bar {7 bar = 'bar'8 #baz: string // private class field9 constructor (baz: string) { this.#baz = baz }10}1112const foo = new Foo()13foo.bar // bar14foo.#baz // Property '#baz' is not accessible outside class 'Foo' because it has a private identifier.1516const bar = new Bar('bar')17bar.bar // bar18bar.#baz // Property '#baz' is not accessible outside class 'Foo' because it has a private identifier.
Use Case
TypeScript provides for us access modifiers (public, protected, private), so why we would be interested in using private fields over private modifier?
Hard privacy
When we use the access modifiers they support development via static code analysis or during compiler time, but after the compilation properties marked with these modifiers behave like any other properties. It means that JS users can get access to the values of these properties.
It's worth noticing that the private access modifier doesn't prevent us from getting the value of the field using bracket notation.
private-modifier1class Foo { private foo = 'foo' }2const foo = new Foo()3console.log(foo['foo']) // fooprivate-fields1class Foo { #foo = 'foo' }2const foo = new Foo()3console.log(foo['#foo']) // undefined and will report an errorUniqueness in scope class
private-modifier1class A {2 private foo = 'foo'3 aHelper () { return this.foo }4}56class B extends A {7 private foo = 'baz'8 bHelper () { return this.foo }9}1011const b = new B()12b.aHelper() // baz13b.bHelper() // bazprivate-fields1class A {2 #foo = 'foo'3 aHelper () { return this.#foo }4}56class B extends A {7 #foo = 'baz'8 bHelper () { return this.#foo }9}1011const b = new B()12b.aHelper() // foo13b.bHelper() // baz
Summary
In opposite to the private modifier, private fields are really private and their behavior is more predictable.
There are also some things worth noticing.
Because fields with private modifier after the compilation are treated as other properties, access to them can be faster in some runtimes than accessing private fields.
TypeScript's private fields support only ES6 target or higher and private fields work even with EcmaScript 3.