Understanding Getters and Setters in TypeScript with Example Code
Getters and Setters
In TypeScript, getters and setters are special methods used to access or modify the values of class properties. They provide a controlled way to interact with object properties, ensuring data integrity and encapsulation.
Getters
- Purpose: Retrieve the value of a property.
- Syntax:
get propertyName(): propertyType {
// Logic to return the property value
return this._propertyName;
}
- Example:
class Person {
private _name: string;
get name(): string {
return this._name;
}
}
In this example, the name
getter allows you to retrieve the value of the _name
property.
set propertyName(value: propertyType) {
// Logic to validate and set the property value
this._propertyName = value;
}
class Person {
private _name: string;
set name(value: string) {
if (value.length > 0) {
this._name = value;
} else {
console.error("Name cannot be empty.");
}
}
}
In this example, the name
setter allows you to set the value of the _name
property, but it also includes validation to ensure that the name is not empty.
Key Points:
- Getters and setters are often used in conjunction with private properties to provide controlled access to class data.
- They can be used to implement custom logic for retrieving or setting property values, such as validation, calculation, or logging.
- Getters and setters can improve code readability and maintainability by separating the logic for accessing and modifying properties from the property declaration itself.
Understanding Getters and Setters in TypeScript with Example Code
Getters and setters are special methods in TypeScript that provide controlled access to class properties. They allow you to encapsulate property logic, perform validations, or calculate values dynamically.
Basic Example:
class Person {
private _name: string;
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
}
const person = new Person();
person.name = "Alice";
console.log(person.name); // Output: Alice
In this example:
_name
is a private property.- The
name
getter returns the value of_name
.
Example with Validation:
class Product {
private _price: number;
get price(): number {
return this._price;
}
set price(value: number) {
if (value < 0) {
throw new Error("Price cannot be negative.");
}
this._price = value;
}
}
const product = new Product();
product.price = 10;
console.log(product.price); // Output: 10
// Try to set a negative price:
product.price = -5; // Throws an error
Here, the setter for price
validates the input value to ensure it's not negative.
class Circle {
private _radius: number;
get radius(): number {
return this._radius;
}
set radius(value: number) {
this._radius = value;
}
get area(): number {
return Math.PI * this._radius * this._radius;
}
}
const circle = new Circle();
circle.radius = 5;
console.log(circle.area); // Output: 78.53981633974483
The area
getter calculates the area of the circle based on the current radius.
- Encapsulation: Getters and setters help encapsulate property logic, making your code more maintainable and secure.
- Validation: You can implement validation rules within setters to ensure data integrity.
- Derived properties: Getters can be used to calculate derived properties based on other properties.
- Controlled access: By using getters and setters, you can control how properties are accessed and modified.
Alternative Approaches to Getters and Setters in TypeScript
While getters and setters provide a structured way to access and modify class properties, there are alternative approaches that can be considered in certain scenarios:
Direct Property Access:
- When: You don't need to perform any validation, calculation, or logging when accessing or modifying the property.
class Person {
name: string;
}
const person = new Person();
person.name = "Alice";
console.log(person.name);
Computed Properties:
- When: You need to dynamically calculate a property value based on other properties or external data.
class Product {
price: number;
taxRate: number;
get totalPrice() {
return this.price * (1 + this.taxRate);
}
}
Object.defineProperty:
- When: You need more granular control over property behavior, including defining property attributes like enumerability, configurability, and writability.
class Person {
constructor() {
Object.defineProperty(this, "name", {
get: () => this._name,
set: (value) => {
if (value.length > 0) {
this._name = value;
} else {
console.error("Name cannot be empty.");
}
},
enumerable: true,
configurable: false
});
}
private _name: string;
}
Method-Based Access:
- When: You want to encapsulate property access and modification logic within methods.
class Person {
private _name: string;
getName() {
return this._name;
}
setName(value: string) {
this._name = value;
}
}
Choosing the Right Approach:
- Simplicity: Direct property access is often the simplest option.
- Flexibility: Computed properties and
Object.defineProperty
provide more flexibility. - Encapsulation: Method-based access can be used for better encapsulation.
typescript