Classes
TypeScript classes are JavaScript classes plus types — and a few time-saving extras like parameter properties. If you know C# or Java, this will feel familiar.
On this page · 5 min · Intermediate
On this page
- Learning objectives
- Explanation
- Syntax
- Code example
- Step by step
- Real-world use
- Common mistakes
- Best practices
- Remember this
- Practice exercise
- Mini quiz
- Related topics
- My notes
- Reading time
- 5 min
- Difficulty
- Intermediate
- Updated
- Oct 28, 2026
Related tutorials
Learning objectives#
- Declare typed properties and constructors
- Use parameter properties to cut boilerplate
- Add readonly fields, getters and setters
- Implement interfaces in classes
Explanation#
Class properties must be declared with their types: name: string;. Under strict mode, every property must be initialised in the declaration or the constructor.
Parameter properties: constructor(private name: string) declares and assigns the property in one step. This shorthand is very common in Angular services.
readonly properties can be set only in the declaration or the constructor.
get and set accessors can validate values; TypeScript types them like properties.
implements InterfaceName makes the compiler check the class against a contract.
Syntax#
class User {
constructor(public readonly id: number, public name: string) {}
greet(): string { return `Hi ${this.name}`; }
}
Code example: A typed product class#
interface Discountable {
applyDiscount(percent: number): void;
}
class Product implements Discountable {
private _price: number;
readonly createdAt = new Date();
constructor(
public readonly id: number,
public name: string,
price: number,
) {
this._price = price;
}
get price(): number {
return this._price;
}
set price(value: number) {
if (value < 0) throw new Error('Price cannot be negative');
this._price = value;
}
applyDiscount(percent: number): void {
this.price = Math.round(this._price * (1 - percent / 100));
}
}
const p = new Product(1, 'Headphones', 2000);
p.applyDiscount(10);
console.log(p.name, p.price); // Headphones 1800
p.id = 5; // ✗ Cannot assign to 'id' because it is a read-only property
p._price = 0; // ✗ Property '_price' is private and only accessible within class 'Product'
new Product(2, 'Mouse'); // ✗ Expected 3 arguments, but got 2
Headphones 1800 — and three compile errors for changing the readonly id, touching the private field and calling the constructor with a missing argument.
This example is illustrative. Copy or download it and run it in your own environment; the expected output is shown above.
Step-by-step explanation#
- Product promises to implement Discountable.
- public readonly id and public name are parameter properties — declared and assigned automatically.
- price is a normal parameter assigned to the private _price.
- The price getter/setter validates new values.
- applyDiscount uses the setter, so validation always runs.
- TypeScript blocks writes to readonly/private members and wrong constructor calls.
Real-world use case#
Angular components and services, NestJS controllers and domain models (Order, Invoice) are TypeScript classes with typed members.
Common mistakes#
Under strict mode, 'name' has no initializer and is not definitely assigned in the constructor. Assign it, give a default, or make it optional.
constructor(name: string) does not create a property. You need public, private, protected or readonly in front.
Passing obj.method as a callback loses this. Use arrow-function properties or bind.
Best practices#
- Use parameter properties for simple constructors
- Mark ids and creation data readonly
- Keep fields private and expose behaviour through methods
- Implement interfaces so classes are swappable in tests
Remember this#
constructor(private x: T) = declare + assign in one go.
readonly = set once, then frozen.
implements = the compiler checks the contract for you.
Practice exercise#
Your task: Write a class BankAccount with a readonly accountNumber, a private balance starting at 0, deposit(amount) and a balance getter. Reject negative deposits.
Need a hint?
Show solution
class BankAccount {
private _balance = 0;
constructor(public readonly accountNumber: string) {}
deposit(amount: number): void {
if (amount <= 0) throw new Error('Deposit must be positive');
this._balance += amount;
}
get balance(): number {
return this._balance;
}
}
Mini quiz#
What does constructor(private name: string) {} do?
Want more? Practise all TypeScript MCQs · TypeScript interview questions
My notes#
Saved in this browser.