Private members in TypeScript classes are considered class-private, not instance-private. This means that inside the body of a class, you can access private members of other instances of the same class. For example:
class Foo {
private bar: number;
constructor(bar: number) { this.bar = bar; }
lessThan(otherFoo: Foo) {
return this.bar < otherFoo.bar
// -------------> ^^^^^^^^^^^^
}
}
const f0 = new Foo(0);
const f1 = new Foo(1);
console.log(f0.lessThan(f1)) // true
console.log(f1.lessThan(f0)) // false
In the above code snippet, referencing otherFoo.bar
is only possible because bar
is private to the Foo
class.
One implication of this behavior is that outside of a class, you can see that a private member exists but cannot access its value. If you were able to access it, you might run into issues like this:
class Qux {
private x = "abc";
y = 123;
method(otherQux: Qux) {
console.log(otherQux.x.toUpperCase())
}
}
const q = new Qux();
q.method({
y: 123,
method: Qux.prototype.method
}) // runtime error
In this example, Qux
has a private property x
and a public property y
, along with a method method
. Trying to access otherQux.x
from outside the class results in a runtime error due to the nature of private members.
Attempting to work around this by adding x
to the object also leads to compiler errors, highlighting the restrictions imposed by using private
properties.
This limitation enforces nominal typing, where objects must be created through specific class constructors to match the intended type. It contrasts with structural typing, where the shape of an object matters more than its declaration.
Link to Playground for code demonstration