How to create getter and setter in interface?
Let’s delve into understanding getters and setters in classes and how to implement them with interfaces.
Defining Getters and Setters
In object-oriented programming, classes often encapsulate data by declaring variables as private
. Access to these variables is then controlled through methods, commonly known as getters and setters. Getters retrieve the value of a private variable, while setters modify it. The get
and set
keywords are used to define these special methods.
Here’s a TypeScript example demonstrating this concept:
class Person {
private _name: string;
constructor() {
}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
In this Person
class, the _name
variable is private. To access or modify its value, we use the getName
and setName
getters and setters.
The Question: Can We Use Regular Functions Instead?
One might wonder if regular functions can achieve the same result as getters and setters:
class Person {
private _name: string;
constructor() {
}
getName(): string {
return this._name;
}
setName(value: string): void {
this._name = value;
}
}
The above code functions correctly. So, what differentiates regular functions from getters and setters?
1. Shared Name: Getters and Setters Can Share the Same Name
A key characteristic is that getters and setters can share the same name. While the function name is arbitrary, it’s conventional to use the name of the variable.
2. Strict Rules: Getters and Setters Must Adhere to Specific Rules
With regular functions, you might implement something like this without issue:
class Person {
private _name: string;
constructor() {
}
getName(postfix: string): string {
return `${this._name}${postfix}`;
}
setName(value: string): string {
this._name = value;
return this._name;
}
}
// It works.
However, if you tried to do the same with getters and setters:
class Person {
private _name: string;
constructor() {
}
get name(postfix: string): string {
return `${this._name}${postfix}`;
}
set name(value: string): string {
this._name = value;
return this._name;
}
}
// error occurs.
Getters and setters must follow specific rules, and violating these rules will result in errors. This helps prevent mistakes and enforces accurate implementation. The rules are as follows:
- Getters cannot accept arguments and must return a value.
- Setters must accept one argument and cannot return a value.
3. Concise Syntax: Getters and Setters Allow Omission of Parentheses
When accessing getters and setters from outside the class, you can omit the parentheses.
Consider the following usage example:
class Main() {
person = new Person();
constructor() {
person.name = 'John'; // setter
let name = person.name; // getter
}
}
In this example, accessing person.name
looks like accessing a variable directly, which is only possible with getters and setters. Regular functions do not offer this syntactic sugar.
Implementing Variables and Functions in Interfaces
Before tackling getter and setter implementation in interfaces, let’s review how to implement variables and functions within interfaces.
Variable Implementation
To implement variables in an interface, you can define their names and types:
interface Person {
name: string;
age: number;
}
Function Implementation
Function implementation involves defining the function signature, including parameters and return type:
interface IPerson {
getName: (postfix: string) => string;
setName: (value: string) => string;
}
Getter and Setter Implementation
Interestingly, interfaces do not directly support getter and setter definitions. The following code will result in an error:
interface IPerson {
get name(): string;
set name(value: string);
}
// Applying this to a class will produce an error:
// src/app/app.component.ts: - error TS1131: Property or signature expected.
// get name(): string;
How can we achieve a similar effect?
The key lies in understanding the purpose of getters and setters: controlling access to private variables. Conversely, public variables don’t necessarily require getters and setters.
Therefore, by declaring a public variable in an interface, we can achieve the same effect as implementing a private variable with associated getters and setters. The compiler will not raise an error.
Here’s how the Person
interface can be defined:
interface IPerson {
name: string;
}
To verify this, let’s implement the IPerson
interface in the Person
class:
class Person implements IPerson {
private _name: string;
constructor(name: string) {
this._name = name;
}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
Running this code confirms that the name
variable declared in the interface effectively acts as a substitute for getter and setter methods.
This approach provides a workaround for the absence of direct getter/setter support in interfaces. There might be even better solutions, so feel free to provide feedback if you have suggestions!
댓글남기기