Skip to Content
Course content

153: Parameter Properties Revisited

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've spent a lot of time reviewing PRs from developers moving from Java or C# to TypeScript, and there is one specific pattern that almost always pops up when they start working with classes. They'll write a constructor, give the arguments types, and then act genuinely confused when those values aren't available in other methods of the class.

Thinking Type Annotations Create Class Members

Here is the classic mistake. You'll see something like this in a codebase:

class UserSession {
  constructor(userId: string, token: string) {
    // The developer thinks they've "defined" the properties here
  }

  isValid() {
    // Error: Property 'token' does not exist on type 'UserSession'
    return this.token !== null;
  }
}

The misconception here is that by adding : string to the constructor argument, you've somehow told TypeScript to create a member variable for the class. You haven't. In this snippet, userId and token are just local variables. They exist only for the duration of the constructor's execution. Once the object is instantiated, those values are gone unless you manually assign them to this.

Now, you could fix this the long way by declaring the properties at the top of the class and doing the boring this.x = x dance. But that's exactly why parameter properties exist.

Using Access Modifiers as Declarations

To turn a constructor argument into a full-fledged class property, you have to prepend it with an access modifier: public, private, protected, or readonly. When you do this, TypeScript does two things behind the scenes: it declares the member on the class, and it automatically assigns the incoming argument to that member.

Let's rewrite that UserSession class using this shorthand:

class UserSession {
  // By adding 'private', we've declared the property and assigned it in one go
  constructor(private userId: string, public token: string) {}

  isValid() {
    // Now this works perfectly!
    return this.token !== null;
  }
}

I personally love this feature because it removes a massive amount of boilerplate. However, a word of caution: don't overdo it if your constructor is taking ten different arguments. While it's concise, a constructor with ten private parameters can become a readability nightmare. In those cases, I usually recommend passing a single "options" object instead.

One last detail: readonly is a powerful addition here. If you know the userId should never change after the session is created, use readonly. It gives you the assignment shorthand while ensuring that no other method in your class accidentally overwrites the ID.

  • public: Accessible from anywhere.
  • private: Accessible only within the class.
  • protected: Accessible within the class and its subclasses.
  • readonly: Cannot be modified after initialization.



📋 Practical Task

Refactoring the InventoryManager for Conciseness

You have been handed a legacy InventoryManager class that is far too verbose. Currently, it manually declares every property and assigns them in the constructor. Your task is to refactor this class to use Parameter Properties to reduce the boilerplate while maintaining the same visibility levels.

class InventoryManager {
  public storeName: string;
  private warehouseId: number;
  protected regionCode: string;
  readonly apiKey: string;

  constructor(storeName: string, warehouseId: number, regionCode: string, apiKey: string) {
    this.storeName = storeName;
    this.warehouseId = warehouseId;
    this.regionCode = regionCode;
    this.apiKey = apiKey;
  }

  getDetails() {
    return `${this.storeName} (ID: ${this.warehouseId})`;
  }
}

Requirements:

  • Remove the explicit property declarations at the top of the class.
  • Remove the manual assignments inside the constructor body.
  • Use access modifiers within the constructor parameters to achieve the exact same functionality.
  • The resulting constructor body should be empty.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.