Declaring getters/setters in Interfaces in TypeScript

avatar

Borislav Hadzhiev

Last updated: Mar 22, 2022

banner

Photo from Unsplash

Declaring getters/setters in Interfaces in TypeScript #

Use the readonly modifier to declare a getter in an interface, e.g. interface Person {readonly name: string;}. Consumers of the interface will only be able to read the property, but they want be able to reassign it.

index.ts
interface Person { readonly name: string; readonly age: number; } const dev1: Person = { name: 'Alice', age: 29, }; console.log(dev1.name); // 👉️ "Alice" // ⛔️ Error: Cannot assign to 'name' because // it is a read-only property. ts(2540) dev1.name = 'Anne'; class Developer implements Person { get name() { return 'Bob'; } get age() { return 30; } } const dev2 = new Developer(); console.log(dev2.name); // 👉️ "Bob" // ⛔️ Error: Cannot assign to 'name' because // it is a read-only property. dev2.name = 'Carl';

The Person interface in the example has 2 readonly properties that serve as a getter.

The dev1 object is of type Person, so its name and age properties can never be reassigned.

In our Developer class, we used an implements clause to indicate that the class is of type Person.

We used getter methods for the name and age properties, so trying to change their values causes an error.

Note that there is no way for us to indicate that the name and age properties in the Person interface will be used specifically as getters.

This is considered an implementation detail, as it shouldn't matter whether we declare a property or a getter, as long as accessing the property returns a value of the correct type.

Technically the class that implements the interface is free to use a property or a getter.

In the same way there is no way for us to specify that a property is a setter in an interface, but we can still use a setter in our class.

index.ts
interface Person { country: string; } class Developer implements Person { private _country = ''; get country() { return this._country; } set country(c: string) { this._country = c; } } const dev = new Developer(); console.log(dev.country); // 👉️ "" dev.country = 'Germany'; console.log(dev.country); // 👉️ "Germany"

The Developer class has a country property that is a getter and setter.

Note that if you only declare a getter for a specific class property, the property is automatically marked as readonly.

You also are not required to specify the type of the setter parameter. If you don't explicitly specify it, it is inferred from the return type of the getter.

index.ts
interface Person { country: string; } class Developer implements Person { private _country = ''; get country() { return this._country; } // 👇️ (parameter) c: string (It's inferred) // from the return type of the getter set country(c) { this._country = c; } } const dev = new Developer(); console.log(dev.country); // 👉️ "" dev.country = 'Germany'; console.log(dev.country); // 👉️ "Germany"

In the same way like with getters, the class is not required to use a getter and setter for the country property.

index.ts
interface Person { country: string; } class Developer implements Person { public country = ''; } const dev = new Developer(); console.log(dev.country); // 👉️ "" dev.country = 'Germany'; console.log(dev.country); // 👉️ "Germany"

We used a basic class property and we still implement the interface correctly.

The reason there is no way for us to specify that a specific property in an interface is a getter or setter is because this is considered an implementation detail.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.