Геттеры и сеттеры в TypeScript: Полное руководство
Полное руководство по геттерам и сеттерам в TypeScript. Изучите синтаксис, валидацию и лучшие практики для доступа к свойствам в классах.
Как реализовать геттеры и сеттеры в TypeScript?
Я пытаюсь создать методы‑геттеры и сеттеры для свойства в TypeScript, но у меня возникают проблемы с синтаксисом. Вот что я пробовал:
private _name: string;
Name() {
get:
{
return this._name;
}
set:
{
this._name = ???;
}
}
Какой правильный синтаксис для реализации геттеров и сеттеров в TypeScript? Какой ключевое слово нужно использовать, чтобы задать значение в сеттере?
ТипScript‑геттеры и сеттеры используют ключевые слова get и set с определённым синтаксисом, который отличается от того, что вы пытались применить. В TypeScript сеттеры автоматически получают значение как параметр, поэтому специального ключевого слова для установки значения не требуется – вы просто используете переданный параметр.
Содержание
- Базовый синтаксис геттеров и сеттеров
- Полные рабочие примеры
- Распространённые ошибки и решения
- Лучшие практики
- Расширенные случаи использования
- Заключение
Базовый синтаксис геттеров и сеттеров
Правильный синтаксис геттеров и сеттеров в TypeScript включает использование ключевых слов get и set перед именами свойств. Вот фундаментальная структура:
class MyClass {
private _propertyName: DataType;
// Метод геттера
get propertyName(): DataType {
return this._propertyName;
}
// Метод сеттера
set propertyName(value: DataType) {
this._propertyName = value;
}
}
Ключевые моменты этого синтаксиса:
- Используйте ключевое слово
getперед именем свойства для методов геттеров - Используйте ключевое слово
setперед именем свойства для методов сеттеров - Метод сеттера автоматически получает присвоенное значение как параметр, обычно называемый
value - Имя свойства в геттере/сеттере должно совпадать с публичным интерфейсом, который вы хотите открыть
Полные рабочие примеры
Простой класс Person
Согласно TypeScriptTutorial.net, вот полностью рабочий пример:
class Person {
private _age: number;
private _firstName: string;
private _lastName: string;
constructor(age: number, firstName: string, lastName: string) {
this._age = age;
this._firstName = firstName;
this._lastName = lastName;
}
// Геттер для возраста
public get age(): number {
return this._age;
}
// Сеттер для возраста с валидацией
public set age(theAge: number) {
if (theAge <= 0 || theAge >= 200) {
throw new Error('The age is invalid');
}
this._age = theAge;
}
// Геттер для полного имени
public get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
// Сеттер для имени
public set firstName(theFirstName: string) {
if (!theFirstName) {
throw new Error('Invalid first name.');
}
this._firstName = theFirstName;
}
}
// Использование
const person = new Person(25, 'John', 'Doe');
console.log(person.age); // 25 (вызывается геттер)
console.log(person.fullName); // John Doe (вызывается геттер)
person.age = 30; // вызывается сеттер
person.firstName = 'Jane'; // вызывается сеттер
Класс Employee с валидацией
Согласно Tektutorialshub, вот как реализовать геттеры и сеттеры с валидацией:
class Employee {
private _emp_Name: string;
private _age_of_emp: number;
private _role: string;
constructor(name: string, age: number, role: string) {
this._emp_Name = name;
this._age_of_emp = age;
this._role = role;
}
// Геттер для имени
get name(): string {
return this._emp_Name;
}
// Сеттер для имени с валидацией
set name(newName: string) {
if (newName.length < 2) {
throw new Error('Name must be at least 2 characters long');
}
this._emp_Name = newName;
}
// Геттер для возраста
get age(): number {
return this._age_of_emp;
}
// Сеттер для возраста с валидацией
set age(newAge: number) {
if (newAge < 18 || newAge > 65) {
throw new Error('Age must be between 18 and 65');
}
this._age_of_emp = newAge;
}
}
// Использование
const emp = new Employee('Alice', 30, 'Developer');
console.log(emp.name); // Alice (вызывается геттер)
emp.name = 'Bob'; // сеттер с валидацией
emp.age = 32; // сеттер с валидацией
Пример вычисляемого свойства
Согласно GeeksforGeeks, вот пример с вычисляемым свойством:
class User {
private _firstName: string;
private _lastName: string;
constructor(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
}
// Геттер для полного имени (вычисляемое свойство)
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
// Сеттер для фамилии
set lastName(newLastName: string) {
if (!newLastName || newLastName.trim() === '') {
throw new Error('Last name cannot be empty');
}
this._lastName = newLastName;
}
}
// Использование
const user = new User('John', 'Smith');
console.log(user.fullName); // John Smith (вызывается геттер)
user.lastName = 'Doe'; // сеттер
console.log(user.fullName); // John Doe (обновлённый геттер)
Распространённые ошибки и решения
Ошибка 1: Неправильная структура синтаксиса
Ваш исходный код пытался объединить геттер и сеттер в один метод, что недопустимо в синтаксисе TypeScript:
// ❌ НЕПРАВИЛЬНО
Name() {
get:
{
return this._name;
}
set:
{
this._name = ???;
}
}
Решение: Используйте отдельные методы get и set:
// ✅ ПРАВИЛЬНО
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
Ошибка 2: Смешение имён свойств
Частая путаница возникает с именованием свойств и параметра в сеттерах.
Решение: Помните, что:
- Имя метода сеттера совпадает с публичным именем свойства
- Параметр сеттера автоматически называется
value(можно переименовать, ноvalueявляется общепринятым)
// ✅ Использование стандартного имени параметра 'value'
set name(value: string) {
this._name = value;
}
// ✅ Переименование параметра (менее привычно)
set name(newName: string) {
this._name = newName;
}
Ошибка 3: Отсутствие типа параметра в сеттере
Забывание указать тип параметра в сеттере может привести к проблемам типобезопасности.
Решение: Всегда указывайте тип параметра:
// ❌ Отсутствует тип параметра
set name(value) {
this._name = value;
}
// ✅ Правильно с типом параметра
set name(value: string) {
this._name = value;
}
Ошибка 4: Неправильный тип возвращаемого значения в геттере
Забывание указать тип возвращаемого значения в геттере.
Решение: Всегда указывайте тип возвращаемого значения:
// ❌ Отсутствует тип возвращаемого значения
get name() {
return this._name;
}
// ✅ Правильно с типом возвращаемого значения
get name(): string {
return this._name;
}
Лучшие практики
1. Используйте приватные свойства с префиксом подчёркивания
Как рекомендует TypeScriptTutorial.net, используйте приватное свойство с префиксом подчёркивания и открывайте его через геттеры/сеттеры:
class MyClass {
private _propertyName: string; // Приватное поле
get propertyName(): string {
return this._propertyName;
}
set propertyName(value: string) {
this._propertyName = value;
}
}
2. Добавляйте валидацию в сеттерах
Используйте сеттеры для добавления логики валидации, как показано в примерах из Tektutorialshub:
set age(value: number) {
if (value < 0) {
throw new Error('Age cannot be negative');
}
this._age = value;
}
3. Используйте только геттеры для чтения
Для свойств, которые должны быть только читаемыми, реализуйте только геттер:
readonly get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
4. Рассмотрите вычисляемые свойства
Создавайте вычисляемые свойства, которые зависят от других свойств, как в примере из GeeksforGeeks:
get fullName(): string {
return `${this._firstName} ${this._lastName}`;
}
5. Соблюдайте соглашения об именовании
Как отмечено в Stack Overflow, придерживайтесь последовательных соглашений:
- Используйте PascalCase для имён свойств геттеров/сеттеров
- Используйте camelCase для приватных полей с префиксом подчёркивания
- Держите имена геттеров/сеттеров простыми и описательными
Расширенные случаи использования
Доступ к свойству с побочными эффектами
Геттеры и сеттеры могут вызывать побочные эффекты при доступе или изменении свойств:
class TemperatureMonitor {
private _currentTemp: number = 20;
private _alertCount: number = 0;
get temperature(): number {
console.log(`Temperature accessed: ${this._currentTemp}°C`);
return this._currentTemp;
}
set temperature(value: number) {
console.log(`Temperature set to: ${value}°C`);
if (value > 30) {
this._alertCount++;
console.warn(`High temperature alert! Total alerts: ${this._alertCount}`);
}
this._currentTemp = value;
}
}
Условные геттеры/сеттеры
Можно условно реализовать геттеры и сеттеры в зависимости от определённых условий:
class Config {
private _apiKey: string;
private _isReadOnly: boolean = false;
get apiKey(): string {
if (this._isReadOnly) {
console.warn('Config is read-only');
}
return this._apiKey;
}
set apiKey(value: string) {
if (this._isReadOnly) {
throw new Error('Cannot modify read-only configuration');
}
this._apiKey = value;
}
public makeReadOnly(): void {
this._isReadOnly = true;
}
}
Использование геттеров/сеттеров с интерфейсами
Определите интерфейсы, которые задают контракт для геттеров и сеттеров:
interface IUser {
get name(): string;
set name(value: string);
get email(): string;
}
class User implements IUser {
private _name: string;
private _email: string;
constructor(name: string, email: string) {
this._name = name;
this._email = email;
}
get name(): string {
return this._name;
}
set name(value: string) {
this._name = value;
}
get email(): string {
return this._email;
}
}
Заключение
Реализация геттеров и сеттеров в TypeScript проста, когда вы понимаете правильный синтаксис:
- Используйте ключевые слова
getиsetперед именем свойства - Указывайте типы параметров и возвращаемых значений для типобезопасности
- Используйте приватные поля с префиксом подчёркивания для инкапсуляции внутреннего состояния
- Добавляйте логику валидации в сеттерах, чтобы обеспечить целостность данных
- Рассмотрите вычисляемые свойства, которые зависят от других полей
Ключевое отличие от вашего первоначального подхода в том, что TypeScript автоматически передаёт значение параметру сеттера, поэтому специального ключевого слова для установки значений не требуется – вы просто используете параметр value (или любое другое имя, которое выберете).
Следуя этим шаблонам, вы сможете создавать надёжные, типобезопасные классы, которые инкапсулируют своё внутреннее состояние и предоставляют контролируемый доступ через чётко определённые интерфейсы. Такой подход повышает целостность данных и делает ваш код более поддерживаемым и самодокументируемым.