Геттеры и сеттеры в TypeScript: как правильно использовать get и set?
Что такое геттеры и сеттеры в TypeScript?
Геттеры (get) и сеттеры (set) — это специальные методы класса, которые позволяют управлять доступом к свойствам объекта. Они выглядят как обычные свойства при использовании, но внутри могут содержать любую логику. Это часть концепции "accessors" (аксессоров) в TypeScript и JavaScript (ES5+).
Основные правила работы с get и set
- Геттер обязан возвращать значение — это функция, которая вызывается при чтении свойства.
- Сеттер принимает ровно один параметр — значение, которое присваивается свойству.
- Геттер и сеттер должны иметь одинаковое имя — иначе TypeScript не свяжет их в одно свойство.
- Нельзя использовать рекурсивные вызовы — внутри сеттера нельзя писать
this.fullName = value, так как это вызовет тот же сеттер снова и приведет к бесконечной рекурсии (Stack Overflow).
Разбор ваших проблем
Проблема 1: undefined при неполных данных
Да, это нормально, потому что ваш код просто берет первый и второй элементы массива. Если в строке только одно слово, то parts[1] будет undefined. Чтобы избежать этого, нужно добавить валидацию:
set fullName(value: string) {
const parts = value.split(' ');
if (parts.length < 2) {
throw new Error('Имя должно содержать имя и фамилию');
}
this.firstName = parts[0];
this.lastName = parts.slice(1).join(' '); // на случай если фамилия составная
}
Проблема 2: рекурсия в сеттере
Если внутри сеттера написать this.fullName = value, то это снова вызовет сеттер, который снова вызовет себя — и так до бесконечности. Используйте приватные поля для хранения данных:
class User {
private _firstName: string = '';
private _lastName: string = '';
get firstName(): string {
return this._firstName;
}
set firstName(value: string) {
if (!value.trim()) {
throw new Error('Имя не может быть пустым');
}
this._firstName = value;
}
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value: string) {
const parts = value.split(' ');
this._firstName = parts[0];
this._lastName = parts.slice(1).join(' ');
}
}
Проблема 3: геттер vs обычный метод
Разница есть, и она важна:
- Геттер — вызывается как свойство:
user.fullName. Не требует круглых скобок. - Метод — вызывается как функция:
user.getFullName(). Требует круглых скобок. - Геттер не может принимать параметры — для этого нужен метод.
- Геттер нельзя использовать с оператором присваивания — если нет сеттера, то
user.fullName = "..."вызовет ошибку.
Best Practices для get и set
- Используйте геттеры для вычисляемых свойств — например, полное имя, возраст из даты рождения, форматированные данные.
- Используйте сеттеры для валидации — проверяйте данные перед сохранением.
- Не злоупотребляйте — если логика сложная, лучше использовать обычные методы.
- Приватные поля с подчеркиванием — это конвенция (
_field), чтобы не путать с публичными аксессорами. - TypeScript поддерживает readonly — если нужно только читать, используйте только геттер без сеттера.
Полный пример с валидацией
class User {
private _firstName: string = '';
private _lastName: string = '';
private _age: number = 0;
get firstName(): string {
return this._firstName;
}
set firstName(value: string) {
if (value.length < 2) {
throw new Error('Имя должно содержать минимум 2 символа');
}
this._firstName = value;
}
get lastName(): string {
return this._lastName;
}
set lastName(value: string) {
if (value.length < 2) {
throw new Error('Фамилия должна содержать минимум 2 символа');
}
this._lastName = value;
}
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
set fullName(value: string) {
const parts = value.trim().split(/\s+/);
if (parts.length < 2) {
throw new Error('Укажите имя и фамилию через пробел');
}
this._firstName = parts[0];
this._lastName = parts.slice(1).join(' ');
}
get age(): number {
return this._age;
}
// Только геттер для ageInMonths — вычисляемое свойство
get ageInMonths(): number {
return this._age * 12;
}
// Сеттер с валидацией
set age(value: number) {
if (value < 0 || value > 150) {
throw new Error('Некорректный возраст');
}
this._age = value;
}
}
// Использование
const user = new User();
user.fullName = "Иван Петров";
user.age = 30;
console.log(user.fullName); // "Иван Петров"
console.log(user.ageInMonths); // 360
Геттеры и сеттеры делают код чище и безопаснее. Главное — помнить про приватные поля и валидацию. Удачи в изучении TypeScript!
<<Альтернативный подход: использование классов без явных геттеров/сеттеров
Не всегда нужно использовать get и set. В TypeScript есть более простые способы инкапсуляции, особенно если вы работаете в команде, где не все знакомы с этой концепцией.
Вариант 1: Обычные методы
class User {
private _firstName: string = '';
private _lastName: string = '';
setFullName(value: string): void {
const [firstName, ...lastNameParts] = value.split(' ');
this._firstName = firstName;
this._lastName = lastNameParts.join(' ') || 'Неизвестно';
}
getFullName(): string {
return `${this._firstName} ${this._lastName}`;
}
}
const user = new User();
user.setFullName("Иван Петров");
console.log(user.getFullName()); // "Иван Петров"
Плюсы: явно видно, что это методы, нет путаницы с рекурсией.
Вариант 2: Публичные поля с readonly
Если вам нужно только читать вычисляемое значение, можно использовать readonly:
class User {
firstName: string;
lastName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
readonly fullName: string = ''; // Не сработает!
// Лучше так: Ответов пока нет.
Войдите чтобы оставить ответ