Bird
Raised Fist0
Typescriptprogramming~15 mins

Getter and setter with types in Typescript - Deep Dive

Choose your learning style10 modes available
Overview - Getter and setter with types
What is it?
Getters and setters are special methods in TypeScript classes that let you read or change the value of a property while controlling how it happens. A getter lets you get a property value like a normal variable, but it runs code behind the scenes. A setter lets you set a property value, also running code to check or change the input. Using types with getters and setters means you tell TypeScript what kind of data these properties hold, helping catch mistakes early.
Why it matters
Without getters and setters, you might directly access or change data in ways that cause bugs or inconsistent states. They help protect your data by controlling how it is read or changed. Adding types makes your code safer and clearer, so you avoid errors like putting a number where a string should be. This leads to more reliable programs and easier maintenance.
Where it fits
Before learning getters and setters with types, you should understand basic TypeScript classes, properties, and type annotations. After this, you can explore advanced class features like access modifiers, readonly properties, and decorators to further control class behavior.
Mental Model
Core Idea
Getters and setters with types let you safely control how class properties are read and changed by wrapping access in typed methods that look like normal property use.
Think of it like...
It's like having a mailbox with a lock: the getter is the slot where you can see or take mail safely, and the setter is the locked door where you put mail in, but only if it fits the right size and shape.
Class Example
┌─────────────────────────────┐
│        MyClass              │
│ ┌───────────────┐          │
│ │ _property     │  (private)│
│ └───────────────┘          │
│ ┌───────────────┐          │
│ │ get property()│  ← getter │
│ └───────────────┘          │
│ ┌───────────────┐          │
│ │ set property()│  ← setter │
│ └───────────────┘          │
└─────────────────────────────┘
Build-Up - 6 Steps
1
FoundationBasic class properties and types
🤔
Concept: Introduce how to declare class properties with types in TypeScript.
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } } const p = new Person('Alice', 30); console.log(p.name); // Alice console.log(p.age); // 30
Result
The class Person has two typed properties: name (string) and age (number). Creating an instance and accessing these properties works as expected.
Understanding how to declare typed properties is the foundation for controlling access with getters and setters.
2
FoundationIntroducing getters and setters syntax
🤔
Concept: Show how to define getter and setter methods in a class to control property access.
class Person { private _name: string; constructor(name: string) { this._name = name; } get name(): string { return this._name; } set name(newName: string) { this._name = newName; } } const p = new Person('Bob'); console.log(p.name); // Bob p.name = 'Charlie'; console.log(p.name); // Charlie
Result
The getter and setter allow reading and updating the private _name property using p.name syntax.
Getters and setters let you control access to private data while keeping a simple property-like interface.
3
IntermediateAdding type safety to getters and setters
🤔Before reading on: do you think TypeScript enforces types on both getter return and setter parameter? Commit to your answer.
Concept: Explain how TypeScript uses types on getter return values and setter parameters to catch errors.
class Person { private _age: number; constructor(age: number) { this._age = age; } get age(): number { return this._age; } set age(newAge: number) { if (newAge < 0) { throw new Error('Age cannot be negative'); } this._age = newAge; } } const p = new Person(25); console.log(p.age); // 25 p.age = 30; // OK // p.age = 'old'; // Error: Type 'string' is not assignable to type 'number'
Result
TypeScript enforces that the getter returns a number and the setter accepts only a number, preventing wrong types.
Knowing that types apply to both getter output and setter input helps prevent bugs and misuse of properties.
4
IntermediateUsing getters and setters for computed properties
🤔Before reading on: do you think getters can compute values dynamically each time they are accessed? Commit to your answer.
Concept: Show how getters can calculate values on the fly instead of just returning stored data.
class Rectangle { constructor(private width: number, private height: number) {} get area(): number { return this.width * this.height; } set area(value: number) { throw new Error('Area is read-only'); } } const rect = new Rectangle(5, 10); console.log(rect.area); // 50 // rect.area = 60; // Error: Area is read-only
Result
The getter calculates area dynamically; the setter throws an error to prevent changes.
Understanding that getters can compute values allows you to create read-only or derived properties.
5
AdvancedCombining private fields with typed getters/setters
🤔Before reading on: do you think private fields (#field) work seamlessly with getters and setters? Commit to your answer.
Concept: Teach how to use modern private fields with getters and setters for better encapsulation and type safety.
class BankAccount { #balance: number; constructor(initialBalance: number) { this.#balance = initialBalance; } get balance(): number { return this.#balance; } set balance(amount: number) { if (amount < 0) { throw new Error('Balance cannot be negative'); } this.#balance = amount; } } const account = new BankAccount(1000); console.log(account.balance); // 1000 account.balance = 1200; // OK // account.#balance = 500; // Error: Private field
Result
Private field #balance is safely accessed and modified only through typed getter and setter.
Knowing how private fields integrate with getters/setters improves data hiding and prevents accidental external changes.
6
ExpertTypeScript type inference and getter/setter compatibility
🤔Before reading on: do you think getter and setter types must exactly match, or can they differ? Commit to your answer.
Concept: Explore how TypeScript infers types for getters and setters and the rules for their compatibility.
class Example { private _value: number | string = 0; get value(): number { return typeof this._value === 'number' ? this._value : 0; } set value(val: number | string) { this._value = val; } } const ex = new Example(); ex.value = 'hello'; console.log(ex.value); // 0 (getter returns number) ex.value = 42; console.log(ex.value); // 42
Result
Getter returns only number, setter accepts number or string; TypeScript enforces getter return type but setter can accept wider types.
Understanding getter/setter type compatibility helps avoid subtle bugs and design flexible APIs.
Under the Hood
At runtime, getters and setters are special methods linked to a property name on the class prototype. When you access the property, the getter method runs and returns a value. When you assign to the property, the setter method runs with the new value. TypeScript uses static analysis to check types during development but compiles to JavaScript where these methods behave like normal functions. Private fields (with #) are enforced by JavaScript engines to be inaccessible outside the class, ensuring true encapsulation.
Why designed this way?
Getters and setters were designed to provide controlled access to object properties without changing how code looks when using them. This keeps code clean and readable while allowing validation, computed values, or side effects. TypeScript adds static typing to catch errors early, improving developer confidence. Private fields were introduced later to fix the problem that 'private' in TypeScript was only compile-time and not enforced at runtime.
Access flow:

Caller code
   │
   ▼
Property access (obj.prop)
   │
   ├─ If getter exists → call getter method → return value
   │
   └─ Else → return stored property value

Property assignment (obj.prop = val)
   │
   ├─ If setter exists → call setter method with val
   │
   └─ Else → set stored property value

TypeScript checks types on getter return and setter parameter at compile time.

Private field (#field) is stored in a hidden slot inaccessible outside class.
Myth Busters - 4 Common Misconceptions
Quick: Does a setter always have to accept the same type as the getter returns? Commit to yes or no.
Common Belief:The setter must accept exactly the same type that the getter returns.
Tap to reveal reality
Reality:The setter can accept a wider or different type than the getter returns, but the getter's return type must be compatible with the declared property type.
Why it matters:Assuming setter and getter types must match exactly can limit design flexibility and cause confusion when building APIs that accept multiple input types but return a normalized output.
Quick: Can you access private fields directly from outside the class? Commit to yes or no.
Common Belief:Private fields declared with # can be accessed or modified from outside the class if you use getters and setters.
Tap to reveal reality
Reality:Private fields with # are truly private and cannot be accessed or modified directly from outside the class, even with getters and setters; only the class methods can access them.
Why it matters:Misunderstanding this can lead to attempts to bypass encapsulation, causing runtime errors or security issues.
Quick: Are getters and setters just syntactic sugar for normal methods? Commit to yes or no.
Common Belief:Getters and setters are just normal methods with special names and no real difference in behavior.
Tap to reveal reality
Reality:Getters and setters behave like properties when accessed or assigned, allowing property-like syntax while running code, which is different from calling methods explicitly.
Why it matters:Confusing them with normal methods can lead to incorrect usage or misunderstanding of how property access triggers code execution.
Quick: Does TypeScript enforce types of getters and setters at runtime? Commit to yes or no.
Common Belief:TypeScript enforces getter and setter types at runtime to prevent wrong data.
Tap to reveal reality
Reality:TypeScript only checks types at compile time; at runtime, JavaScript runs without type checks, so runtime errors can still occur if code is incorrect.
Why it matters:Relying solely on TypeScript for runtime safety can cause bugs; additional runtime checks or tests are needed for full safety.
Expert Zone
1
Getters and setters can be used to create virtual properties that do not store data but compute or transform it dynamically, enabling powerful abstractions.
2
TypeScript's structural typing means that objects with compatible getter/setter signatures can be assigned interchangeably, which can lead to subtle bugs if not carefully designed.
3
Using private fields (#) with getters/setters ensures true encapsulation at runtime, unlike TypeScript's private keyword which is only compile-time enforced.
When NOT to use
Avoid getters and setters when simple public properties suffice without validation or computation, as they add overhead and complexity. For complex state management or side effects, consider using methods or reactive frameworks instead. Also, do not use getters/setters for asynchronous operations since they must return immediately.
Production Patterns
In real-world TypeScript projects, getters and setters are used to enforce validation rules, lazy-load computed values, or trigger side effects like logging. Private fields combined with getters/setters protect sensitive data. Libraries often use them to create clean APIs that hide internal complexity while maintaining type safety.
Connections
Encapsulation in Object-Oriented Programming
Getters and setters implement encapsulation by controlling access to object data.
Understanding getters and setters deepens your grasp of encapsulation, a core OOP principle that protects object integrity.
Property Accessors in C#
TypeScript getters and setters are similar to C# property accessors, both providing controlled property access with type safety.
Knowing how other languages implement property accessors helps appreciate TypeScript's design and cross-language patterns.
Security Checks in Physical Locks
Getters and setters act like security checks controlling who can read or write data, similar to locks controlling physical access.
Recognizing this connection highlights the importance of controlled access in both software and real-world security.
Common Pitfalls
#1Setting a property with the wrong type causes runtime errors.
Wrong approach:class Person { private _age: number = 0; get age(): number { return this._age; } set age(value: number) { this._age = value; } } const p = new Person(); p.age = 'old'; // No compile error if type is any or missing, causes runtime issues
Correct approach:class Person { private _age: number = 0; get age(): number { return this._age; } set age(value: number) { this._age = value; } } const p = new Person(); p.age = 30; // Correct type assignment
Root cause:Not specifying or enforcing types on setter parameters allows wrong types to be assigned, leading to bugs.
#2Trying to access private fields directly from outside the class.
Wrong approach:class Account { #balance = 100; } const acc = new Account(); console.log(acc.#balance); // Syntax error
Correct approach:class Account { #balance = 100; get balance() { return this.#balance; } } const acc = new Account(); console.log(acc.balance); // 100
Root cause:Misunderstanding that private fields are truly private and require access through class methods.
#3Defining only a setter without a getter causes unexpected behavior.
Wrong approach:class Example { set value(val: number) { console.log('Set', val); } } const ex = new Example(); ex.value = 10; console.log(ex.value); // undefined, no getter defined
Correct approach:class Example { private _val = 0; get value(): number { return this._val; } set value(val: number) { this._val = val; } } const ex = new Example(); ex.value = 10; console.log(ex.value); // 10
Root cause:Forgetting to define a getter means reading the property returns undefined, confusing users.
Key Takeaways
Getters and setters let you control how class properties are read and written while keeping simple property syntax.
TypeScript enforces types on getter return values and setter parameters to catch errors early and improve code safety.
Getters can compute values dynamically, and setters can validate or transform input before storing it.
Private fields combined with getters and setters provide true encapsulation and protect internal data.
Understanding the runtime behavior and TypeScript's static checks helps avoid common mistakes and design robust APIs.

Practice

(1/5)
1.

What is the main purpose of using getter and setter in TypeScript classes?

easy
A. To make functions run faster
B. To create new classes automatically
C. To control how properties are accessed and modified with type safety
D. To declare variables without types

Solution

  1. Step 1: Understand getter and setter roles

    Getters and setters allow controlled access to class properties, letting you add logic when reading or writing values.
  2. Step 2: Recognize type safety benefit

    Using types with getters and setters ensures only valid data is assigned or returned, keeping data safe.
  3. Final Answer:

    To control how properties are accessed and modified with type safety -> Option C
  4. Quick Check:

    Getter and setter purpose = control access + type safety [OK]
Hint: Getters/setters control property access safely [OK]
Common Mistakes:
  • Thinking getters/setters create new classes
  • Believing they improve function speed
  • Confusing them with variable declarations
2.

Which of the following is the correct syntax to define a typed getter for a property name of type string in a TypeScript class?

class Person {
  private _name: string;

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

  // What is the correct getter syntax here?
}
easy
A. get name(): string { return this._name; }
B. get name { return this._name; }
C. getter name(): string { return this._name; }
D. get name(): void { return this._name; }

Solution

  1. Step 1: Recall getter syntax in TypeScript

    The getter uses the keyword get, followed by the property name, parentheses, and a return type.
  2. Step 2: Check return type matches property type

    The getter must return a string since _name is a string.
  3. Final Answer:

    get name(): string { return this._name; } -> Option A
  4. Quick Check:

    Getter syntax = get + name() + return type [OK]
Hint: Getter needs 'get', name(), and correct return type [OK]
Common Mistakes:
  • Omitting parentheses after getter name
  • Using wrong keyword like 'getter'
  • Setting return type to void instead of string
3.

What will be the output of the following TypeScript code?

class Counter {
  private _count: number = 0;

  get count(): number {
    return this._count;
  }

  set count(value: number) {
    if (value >= 0) {
      this._count = value;
    }
  }
}

const c = new Counter();
c.count = 5;
c.count = -3;
console.log(c.count);
medium
A. undefined
B. 5
C. 0
D. -3

Solution

  1. Step 1: Analyze setter behavior

    The setter only updates _count if the new value is >= 0. Setting to 5 updates it, setting to -3 is ignored.
  2. Step 2: Check final value returned by getter

    The getter returns the current _count, which remains 5 after the invalid -3 assignment.
  3. Final Answer:

    5 -> Option B
  4. Quick Check:

    Setter blocks negative, final count = 5 [OK]
Hint: Setter blocks negative values, so count stays 5 [OK]
Common Mistakes:
  • Assuming setter accepts negative values
  • Expecting count to be -3 after invalid set
  • Confusing initial value with final output
4.

Identify the error in this TypeScript class using getter and setter:

class User {
  private _age: number;

  get age(): number {
    return this._age;
  }

  set age(value: string) {
    this._age = Number(value);
  }
}
medium
A. Setter parameter type should be number, not string
B. Getter must return string, not number
C. Private property _age should be string
D. Setter cannot convert string to number

Solution

  1. Step 1: Compare getter and setter types

    The getter returns a number, so the setter should accept a number to keep types consistent.
  2. Step 2: Identify mismatch in setter parameter

    The setter takes a string but assigns to a number property, causing a type mismatch.
  3. Final Answer:

    Setter parameter type should be number, not string -> Option A
  4. Quick Check:

    Setter param type must match property type [OK]
Hint: Setter param type must match property type [OK]
Common Mistakes:
  • Allowing setter param type different from property
  • Thinking getter return type should change
  • Believing setter can't convert types
5.

Given this TypeScript class, what will console.log(user.fullName); output?

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 fullName(name: string) {
    const parts = name.split(' ');
    if (parts.length === 2) {
      [this._firstName, this._lastName] = parts;
    }
  }
}

const user = new User('Jane', 'Doe');
user.fullName = 'John Smith';
console.log(user.fullName);
hard
A. Jane Doe
B. Jane Smith
C. John Doe
D. John Smith

Solution

  1. Step 1: Understand setter logic

    The setter splits the input string by space and updates _firstName and _lastName only if there are exactly two parts.
  2. Step 2: Apply setter and check getter output

    Setting fullName to 'John Smith' updates the names. The getter then returns 'John Smith'.
  3. Final Answer:

    John Smith -> Option D
  4. Quick Check:

    Setter splits and updates names, getter returns combined string [OK]
Hint: Setter splits fullName, getter joins first and last [OK]
Common Mistakes:
  • Assuming original names stay after setter call
  • Expecting only first or last name to change
  • Ignoring setter condition on split length
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard