Rames
Rames

Reputation: 393

Why is protected keyword not preserved for abstract properties in typescript

I'm not sure if this is a possible bug in TypeScript or if it's working by design. I have an Angular project in which I have 3 classes. 1 abstract service, 1 service implementing the abstract service and 1 component using the implementing service.

Simplified, my classes look like this:

export abstract class BaseApiService {
  constructor() { }
  protected abstract baseUrl: string;
export class LogApiService extends BaseApiService {
  baseUrl = environment.apiBaseUrl;
  constructor() { }
}
export class LogPageComponent implements OnInit {

  constructor(private logApiService: LogApiService) { }

  ngOnInit(): void {
    this.logApiService.baseUrl = 'why can I change this?';
  }

}

Since i have added the protected keyword to the baseUrl property in BaseApiService, I'd expect the property to be mutable in LogApiService, but immutable in LogPageComponent. This is not the case. The code above in LogPageComponent's ngOnInit function compiles and runs without issue.
I can prevent LogPageComponent from being able to change LogApiService's baseUrl property by adding the protected keyword inside LogApiService like so: protected baseUrl = environment.apiBaseUrl;.

It feels like a bug to me that I have to add the protected keyword in both BaseApiService and LogPageComponent, but might of course be by design. Is there a reason for this behavior, or should I report it as a bug on Github in the TypeScript repo?

Upvotes: 2

Views: 731

Answers (1)

Benzara Tahar
Benzara Tahar

Reputation: 2217

That's the normal behavior and it occurs because you are changing the visibility of the inherited and protected member:

// here you are removing the protected keywork and making it public
baseUrl = environment.apiBaseUrl;

You can make a protected field public because protected allows a derived class to read and write a field. The derived class can choose to use its ability to read and write the field to allow others to read and write the field.

In the same way, You can not make a private field protected or public because you don't have read or write access to that field.

UPDATE:

if you don't want to set the protected keyword each time then you have to not override the field and manipulate it directly in the constructor like this:

export class LogApiService extends BaseApiService {
   // remove this => baseUrl = environment.apiBaseUrl;
  constructor() { 
   super();
   this.baseUrl = environment.apiBaseUrl;
 }
}

Upvotes: 4

Related Questions