Skip to content
JL

Home

About

Blog

Contact

Shop

Portfolio

Privacy

TOS

Click to navigate

  1. Home
  2. Joshua R. Lehman's Blog
  3. Parameter Properties Shorthand in TypeScript

Table of contents

  • Share on X
  • Discuss on X

Related Articles

Access Modifiers: public, private, protected
TypeScript
8m
Feb 15, 2026

Access Modifiers: public, private, protected

A comprehensive guide to TypeScript access modifiers covering public, private, and protected keywords with practical examples of encapsulation and data protection.

#Access Modifiers#Encapsulation+5
Classes in TypeScript: The Basics
TypeScript
7m
Feb 8, 2026

Classes in TypeScript: The Basics

A comprehensive introduction to TypeScript classes covering properties, methods, constructors, and object instantiation with type safety.

#TypeScript Classes#OOP+5
Getters, Setters, and Computed Properties
TypeScript
7m
Feb 22, 2026

Getters, Setters, and Computed Properties

A comprehensive guide to TypeScript accessor methods covering getters, setters, computed properties, validation patterns, and best practices for controlled property access.

#TypeScript Getters#TypeScript Setters+5
Ask me anything! 💬

© Joshua R. Lehman

Full Stack Developer

Crafted with passion • Built with modern web technologies

2026 • All rights reserved

Contents

  • What Are Parameter Properties
  • The Shorthand Syntax
  • Access Modifiers as Parameters
  • Readonly Parameter Properties
  • Mixing Regular and Parameter Properties
  • Real-World Patterns
  • Best Practices
  • Key Takeaways
TypeScript

Parameter Properties Shorthand in TypeScript

March 29, 2026•6 min read
Joshua R. Lehman
Joshua R. Lehman
Author
TypeScript parameter properties shorthand visualization
Parameter Properties Shorthand in TypeScript

What Are Parameter Properties

TypeScript constructors often require a familiar ritual: declare properties at the top of the class, list parameters in the constructor, then assign each parameter to this.property one by one. For a class with five properties, that's fifteen lines just to get started.

Parameter properties collapse all three steps into one. By adding an access modifier — public, private, protected, or readonly — to a constructor parameter, TypeScript automatically declares the class property and assigns the incoming value. No separate declaration, no manual assignment.

// Before: 12 lines of setup for three properties
class ProductBefore {
  private name: string;
  private price: number;
  private inStock: boolean;
 
  constructor(name: string, price: number, inStock: boolean) {
    this.name = name;
    this.price = price;
    this.inStock = inStock;
  }
}
 
// After: parameter properties shorthand
class Product {
  constructor(
    private name: string,
    private price: number,
    private inStock: boolean
  ) {}
}

Same result, less noise. Both classes are identical at runtime.

What Makes It a Parameter Property

Adding an access modifier (public, private, protected) or readonly to a constructor parameter tells TypeScript to: 1) declare a class property with that name and type, and 2) assign the constructor argument to it automatically. Without a modifier, the parameter is just a regular local variable.

The Shorthand Syntax

The rule is simple: any constructor parameter prefixed with public, private, protected, or readonly becomes a parameter property — declared and initialized in one step.

class Point {
  constructor(
    public x: number,
    public y: number
  ) {}
}
 
const origin = new Point(0, 0);
console.log(origin.x); // 0
console.log(origin.y); // 0

The empty constructor body {} is intentional — TypeScript handles the property assignment implicitly. You only add code there when you need additional initialization logic beyond simple assignment.

Access Modifiers as Parameters

All four access modifiers work as parameter properties, each behaving exactly as it would on a regular class property:

class BankAccount {
  constructor(
    public readonly id: string, // accessible everywhere, immutable after construction
    public owner: string, // accessible from anywhere
    protected balance: number, // accessible in this class and subclasses
    private pin: string // accessible only within this class
  ) {}
 
  deposit(amount: number): void {
    this.balance += amount;
  }
 
  validatePin(input: string): boolean {
    return this.pin === input;
  }
}
 
const account = new BankAccount("ACC-001", "Alice", 1000, "1234");
 
console.log(account.id); // "ACC-001"
console.log(account.owner); // "Alice"
// account.balance          // Error: property 'balance' is protected
// account.pin              // Error: property 'pin' is private

Combine readonly with any modifier

public readonly is one of the most useful combinations. It exposes a property for external reading while preventing accidental reassignment after the object is constructed — ideal for IDs, configuration values, and injected dependencies.

Readonly Parameter Properties

readonly can stand alone (defaulting to public) or combine with private or protected. It prevents reassignment after construction:

class AppConfig {
  constructor(
    readonly apiUrl: string, // public readonly (implicit)
    private readonly apiKey: string, // private readonly
    readonly timeout: number = 30000 // with a default value
  ) {}
 
  getHeaders(): Record<string, string> {
    return { Authorization: `Bearer ${this.apiKey}` };
  }
}
 
const config = new AppConfig("https://api.example.com", "secret-key");
 
console.log(config.apiUrl); // "https://api.example.com"
// config.apiUrl = "other";    // Error: cannot assign to 'apiUrl' because it is a read-only property

readonly Does Not Mean Deeply Immutable

readonly prevents reassigning the property reference, but if the value is an object or array, its contents can still be mutated. For deep immutability, use Readonly<T> or as const on the value itself.

Mixing Regular and Parameter Properties

Not every constructor parameter needs to become a class property. You can freely mix regular parameters (no modifier) with parameter properties:

class Rectangle {
  area: number;
 
  constructor(
    public width: number, // becomes a property
    public height: number, // becomes a property
    label: string // regular parameter — NOT stored on the class
  ) {
    this.area = width * height;
    console.log(`Created ${label} rectangle`);
  }
}
 
const rect = new Rectangle(10, 20, "landscape");
console.log(rect.width); // 10
console.log(rect.height); // 20
console.log(rect.area); // 200
// rect.label             // Error: property does not exist

label is used only inside the constructor and discarded afterward — it never becomes a class property. This pattern is useful when you need a parameter for initialization logic but don't need to store it.

Real-World Patterns

Parameter properties are especially effective in service classes that receive dependencies through their constructor:

class UserService {
  constructor(
    private readonly db: Database,
    private readonly cache: CacheClient,
    private readonly logger: Logger,
    private readonly config: AppConfig
  ) {}
 
  async findUser(id: string): Promise<User | null> {
    const cached = await this.cache.get(`user:${id}`);
    if (cached) return cached;
 
    const user = await this.db.query<User>(
      `SELECT * FROM users WHERE id = $1`,
      [id]
    );
 
    if (user) {
      await this.cache.set(`user:${id}`, user, this.config.cacheTtl);
      this.logger.info(`User ${id} fetched from database`);
    }
 
    return user;
  }
}

Four dependencies. Four lines. No separate property declarations, no this.x = x assignments. Dependency injection patterns like this are where parameter properties save the most boilerplate.

Best Practices

Use parameter properties when:

  • A constructor parameter maps directly to a stored property (1-to-1 relationship)
  • You want to reduce boilerplate in simple data or value classes
  • Injecting dependencies into a service, repository, or controller

Use explicit property declarations when:

  • The stored value is transformed from the incoming parameter
  • Complex initialization logic is needed before assignment
  • The class has many properties and explicit declarations improve readability
// Good candidate for shorthand — direct assignment
class Coordinates {
  constructor(
    public readonly lat: number,
    public readonly lng: number
  ) {}
}
 
// Better with an explicit property — value is transformed before storing
class Temperature {
  private readonly kelvin: number;
 
  constructor(celsius: number) {
    this.kelvin = celsius + 273.15; // transformation, not direct assignment
  }
 
  toCelsius(): number {
    return this.kelvin - 273.15;
  }
}

Many teams adopt a simple convention: use parameter properties for dependency injection and plain data classes, explicit properties everywhere else. Consistency within a codebase matters more than the specific choice.

Key Takeaways

  • Add public, private, protected, or readonly to a constructor parameter to make it a parameter property
  • TypeScript declares the class property and assigns the constructor argument automatically — no this.x = x needed
  • All four modifiers work, and readonly can combine with any of them
  • Regular parameters (no modifier) and parameter properties can be freely mixed in the same constructor
  • Best suited for direct 1-to-1 assignments — use explicit properties when you need to transform the value or run complex initialization logic

Phase 3 Complete

You've finished the Classes and OOP phase of this series. You now know TypeScript classes from the ground up: properties, methods, access modifiers, getters and setters, static members, abstract classes, inheritance, interface implementation, and parameter properties shorthand. Up next: Union Types and the start of TypeScript's advanced type system.