In TypeScript, access modifiers are used to restrict the visibility of properties and methods within classes:
class Animal { public name: string; private age: number; protected kind: string; constructor(name: string, age: number, kind: string) { this.name = name; this.age = age; this.kind = kind; } } class Dog extends Animal { bark() { console.log(this.kind); // OK: protected // console.log(this.age); // Error: private not visible in subclass } } const dog = new Dog('Sharik', 5, 'mammal'); console.log(dog.name); // OK // console.log(dog.kind); // Error: protected // console.log(dog.age); // Error: private
#field, but this is already in the JS specification and compiles differently.Question: Can you access a private property of a TypeScript class after compilation to JavaScript?
Answer: Yes, because private (and protected) are checks from TypeScript at compile time, after compilation to ES5 or ES6, privacy is not maintained, properties remain in the object and can be accessed by property name (for example, via object['privateProp']).
// JS code after compilation function Animal(name, age, kind) { this.name = name; this.age = age; this.kind = kind; } var dog = new Animal('Sharik', 5, 'mammal'); console.log(dog['age']); // 5 — no access only at TS level!
Story
In a large project, a developer relied on the inaccessibility of private fields at runtime. As a result, when passing an object via serialization (JSON.stringify) to logs, confidential data accidentally leaked, as TS typing did not protect against actual access to fields.
Story
A mechanism for "extending" class instances through dynamically adding properties was implemented in the project. Dynamically added properties overwrote private names and were accidentally modified by external code. The error was discovered only in production, and privacy was not ensured.
Story
When migrating from JavaScript to TypeScript, the team started using protected, believing it protected against the usage of fields outside of child classes. However, a programmer mistakenly overwrote a protected field at runtime via
Object.assign, leading to a hard-to-trace bug. This became possible because run-time encapsulation was absent.