Question

TypeScript Getters and Setters: How to Use get and set Correctly

Question

I am trying to create getter and setter methods for a property in TypeScript.

private _name: string;

Name() {
    get: {
        return this._name;
    }
    set: {
        this._name = ???;
    }
}

What is the correct syntax for defining a getter and setter, and what value does the setter receive?

Short Answer

By the end of this page, you will understand how to define getters and setters in TypeScript, how setter parameters work, and how accessors are used like normal properties rather than regular methods.

Concept

In TypeScript, getters and setters are special class members called accessors. They let you control how a property is read and updated.

A getter runs when code reads a property. A setter runs when code assigns a value to a property.

This is useful because you can:

  • hide internal fields such as _name
  • validate values before saving them
  • compute values dynamically
  • keep a simple property-style API for users of your class

In TypeScript, getters and setters are declared with the get and set keywords directly on class members. They are not written inside another method.

A setter receives the new assigned value as a parameter. You choose the parameter name.

For example:

class Person {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

Here:

  • get name() returns the current value
  • set name(value: string) receives the new value in the value parameter

This matters in real programming because many classes need to protect their internal state. Instead of letting outside code directly change fields in unsafe ways, accessors give you a controlled entry point.

Mental Model

Think of a class like a building with a reception desk.

  • The private field _name is a file stored in a back office.
  • The getter is the receptionist who fetches the file when someone asks for it.
  • The setter is the receptionist who checks and stores a new file when someone delivers one.

Outside code does not touch the back office directly. It talks to the receptionist through the property.

That means you can later add rules, such as:

  • reject empty names
  • trim extra spaces
  • log changes

without changing how other code uses the property.

Take Quiz

Syntax and Examples

Basic syntax

class Person {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

Using the accessor

const person = new Person();
person.name = "Ava";      // calls the setter
console.log(person.name);  // calls the getter

Even though name uses get and set, you use it like a normal property.

Example with validation

class Person {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    if (value.trim() === "") {
      throw new Error("Name cannot be empty");
    }

    this._name = value.trim();
  }
}

const person = new Person();
person.name = "  Maya  ";
console.log(person.name); // "Maya"

This example shows why accessors are useful: the setter can clean and validate input before storing it.

Step by Step Execution

Consider this code:

class Person {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

const person = new Person();
person.name = "Leo";
console.log(person.name);

Step by step:

  1. const person = new Person();

    • A new Person object is created.
    • _name starts as "".
  2. person.name = "Leo";

    • This does not directly assign to a public field.
    • It calls the setter: set name(value: string).
    • Inside the setter, value is "Leo".
    • The setter runs this._name = value;.
    • _name is now "Leo".
  3. console.log(person.name);

    • This calls the getter: get name(): string.
    • The getter returns this._name.
    • The printed result is Leo.

Tiny trace

LineActionResult
new Person()Create object_name = ""
person.name = "Leo"Call setter_name = "Leo"
person.nameCall getterreturns "Leo"

Real World Use Cases

Getters and setters are common when a class should expose a clean property API while controlling internal data.

Common use cases

  • Form models: trim and validate user input before saving it
  • Configuration objects: reject invalid settings
  • API response wrappers: transform raw data into cleaner values
  • Domain models: enforce business rules such as age must be positive
  • Computed properties: return a value based on other fields

Example: validating configuration

class AppConfig {
  private _port: number = 3000;

  get port(): number {
    return this._port;
  }

  set port(value: number) {
    if (value < 1 || value > 65535) {
      throw new Error("Invalid port number");
    }
    this._port = value;
  }
}

This lets the rest of the app use config.port naturally, while still enforcing rules.

Take Quiz

Real Codebase Usage

In real projects, developers often use getters and setters for encapsulation and validation, but usually only when there is a clear reason. If a property needs no custom logic, a normal public field may be simpler.

Common patterns

Validation in setters

set email(value: string) {
  if (!value.includes("@")) {
    throw new Error("Invalid email address");
  }
  this._email = value;
}

Normalizing values

set username(value: string) {
  this._username = value.trim().toLowerCase();
}

Read-only computed getter

class Rectangle {
  constructor(public width: number, public height: number) {}

  get area(): number {
    return this.width * this.height;
  }
}

Backing field convention

Developers often store the real value in a private field such as:

  • _name
  • _email
  • _port

and expose a cleaner public accessor such as:

  • name
  • email
  • port

When not to use them

Avoid getters and setters when they add no value. If your code just stores and returns a value with no validation or transformation, a public property may be enough.

Common Mistakes

1. Writing accessors inside a method

This is invalid:

class Person {
  private _name: string = "";

  Name() {
    get: {
      return this._name;
    }
    set: {
      this._name = ???;
    }
  }
}

Getters and setters must be declared as class members:

class Person {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

2. Forgetting the setter parameter

Broken:

set name() {
  this._name = value;
}

Correct:

set name(value: string) {
  this._name = value;
}

3. Calling an accessor like a method

Broken:

person.name("Ava");
console.log(person.name());

Correct:

person.name = "Ava";
console.log(person.name);

4. Accidentally causing infinite recursion

Broken:

class Person {
  set name(value: string) {
    this.name = value; // calls the setter again and again
  }
}

Correct:

class Person {
  private _name: string = "";

  set name(value: string) {
    this._name = value;
  }
}

5. Using different types for getter and setter carelessly

Keep the API clear and consistent unless you have a strong reason not to.

get name(): string {
  return this._name;
}

set name(value: string) {
  this._name = value;
}

Comparisons

ConceptHow it is usedBest for
Public propertyperson.name = "Ava"Simple storage with no extra logic
Getter and setterperson.name = "Ava", person.nameValidation, formatting, controlled access
Regular methodsperson.setName("Ava"), person.getName()Explicit actions or when property syntax is not desired

Getter/setter vs traditional methods

class PersonWithMethods {
  private _name: string = "";

  getName(): string {
    return this._name;
  }

  setName(value: string) {
    this._name = value;
  }
}
class PersonWithAccessors {
  private _name: string = "";

  get name(): string {
    return this._name;
  }

  set name(value: string) {
    this._name = value;
  }
}

Accessors usually feel more natural because they are used like properties.

private _name vs public name

  • private _name stores the actual internal data.
  • name exposes a safe public interface.

That separation helps you change the internal implementation later without changing outside code.

Take Quiz

Cheat Sheet

Basic syntax

class Example {
  private _value: string = "";

  get value(): string {
    return this._value;
  }

  set value(newValue: string) {
    this._value = newValue;
  }
}

Usage

const e = new Example();
e.value = "hello";   // setter
console.log(e.value); // getter

Rules

  • Use get propertyName() to define a getter.
  • Use set propertyName(parameter) to define a setter.
  • The setter receives the assigned value as its parameter.
  • Accessors are declared directly in the class, not inside another method.
  • Use accessors like properties, not like function calls.
  • Use a private backing field such as _name to avoid recursion.

Common pattern

private _name: string = "";

get name(): string {
  return this._name;
}

set name(value: string) {
  this._name = value;
}

Watch out for

  • this.name = value inside set name(...) causes recursion
  • person.name() is wrong for an accessor
  • A setter must have exactly one parameter

FAQ

What is the parameter name in a TypeScript setter?

You choose the name yourself. Common choices are value, newValue, or something descriptive like name.

Do I need both a getter and a setter?

No. You can define only a getter for read-only access, or both if the property should be writable.

How do I call a getter in TypeScript?

You do not call it like a method. Use property access:

console.log(person.name);

How do I call a setter in TypeScript?

Assign to the property:

person.name = "Ava";

Why use _name instead of name internally?

Because the accessor is already named name. Using _name avoids calling the getter or setter recursively.

Can a getter compute a value instead of returning a stored field?

Yes. A getter can calculate and return a value each time it is accessed.

Are getters and setters the same as normal methods?

No. They look like methods in class syntax, but they are used like properties.

Take Quiz

Mini Project

Description

Build a small UserProfile class that stores a username safely. The project demonstrates how to use a private backing field with a getter and setter, and how to validate input before saving it.

Goal

Create a class whose username property can be read and updated safely using TypeScript accessors.

Requirements

  • Create a class named UserProfile.
  • Store the real value in a private field.
  • Add a getter named username that returns the current username.
  • Add a setter named username that rejects empty values.
  • Trim whitespace before saving the username.
Take Quiz

Keep learning

Related questions

View more