Borislav Hadzhiev
Fri Mar 25 2022·3 min read
Photo by Kalen Emsley
The error "Property is private in type 'X' but not in type 'Y'" occurs when the visibility of a property is changed when a class extends another or implements an interface. To solve the error, use a setter and a getter with custom logic that suits your use case.
Here are 2 examples of how the error occurs.
class Person { constructor(private name: string, private age: number) {} } // ⛔️ Class 'Developer' incorrectly extends base class 'Person'. // Property 'name' is private in type 'Person' but not in type 'Developer'.ts(2415) class Developer extends Person { // 👇️ can't change visibility here constructor(public name: string, public age: number) { super(name, age); } } // ------------------------------------------------------------- interface Employee { salary: number; } // ⛔️ Class 'Tester' incorrectly implements interface 'Employee'. // Property 'salary' is private in type 'Tester' but not in type 'Employee'.ts(2420) class Tester implements Employee { // 👇️ can't change visibility here private salary = 0; }
In the first example, the Person
class has a name
and age
private
properties.
Developer
class that extends from Person
tries to change the visibility of the properties and re-declares them.We aren't allowed to change the visibility when extending a class or
implementing an interface. To solve the error in this example, we have to remove
the public
modifier.
class Person { constructor(private name: string, private age: number) {} } class Developer extends Person { constructor(name: string, age: number) { super(name, age); } }
Private members are only accessible within the class. If you want to make the properties accessible inside of the subclass, you can change their visibility to protected.
class Person { // 👇️ protected (accessible in subclasses) constructor(protected name: string, protected age: number) {} } class Developer extends Person { constructor(name: string, age: number) { super(name, age); } logProps() { console.log(this.name); console.log(this.age); } }
If you need the class properties to be accessible from the outside, set them to public.
Another cause of the "Property is private in type 'X' but not in type 'Y'" error is when a class implements an interface and tries to set a property to private visibility.
interface Employee { salary: number; } // ⛔️ Class 'Tester' incorrectly implements interface 'Employee'. // Property 'salary' is private in type 'Tester' but not in type 'Employee'.ts(2420) class Tester implements Employee { private salary = 0; }
Interfaces
aren't allowed to define private
or protected
properties, because they are
only concerned with the structure and capabilities of types.
If you need to declare a property that cannot be reassigned, use the readonly modifier.
interface Employee { salary: number; } class Tester implements Employee { // 👇️ is readonly readonly salary = 0; } const tester = new Tester(); console.log(tester.salary); // 👉️ 0 // ⛔️ cannot reassign a read-only property tester.salary = 100;
The salary
property can still be accessed from the outside, but it cannot be
reassigned.
Alternatively, you can use a setter and a getter.
interface Employee { salary: number; } class Tester implements Employee { // 👇️ private (only accessible in this class) private _salary = 0; // 👇️ accessible from outside get salary() { // 👉️ your implementation return this._salary; } // 👇️ protected (can access in subclass) protected set salary(num: number) { this._salary = num; } } const tester = new Tester(); console.log(tester.salary); // 👉️ 0
Consumers can still access the salary
property from the outside, but you are
able to provide an implementation for the getter method. For example, you could
throw a helpful error message if you want to forbid this.
The _salary
property is private
and only accessible from within the class.
The salary
setter is protected
, so it is accessible inside of the class and
its subclasses.