Reputation: 393
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
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