Classes in TypeScript
Typed class properties, constructor parameter properties, access modifiers, and implementing interfaces.
3 min read
TypeScript classes build on JavaScript classes with typed properties, access modifiers that control visibility, and a shorthand for declaring properties directly in the constructor.
Typed properties
class User {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const user = new User("Ada", 36);Every property needs a declared type (or one TypeScript can infer from an initial value), and the constructor's parameters are typed exactly like a regular function's.
Constructor parameter properties: a shorthand
Writing name: string twice — once as a class property, once as a constructor parameter — is repetitive enough that TypeScript provides a shortcut: adding an access modifier directly to a constructor parameter declares and assigns it in one step.
class User {
constructor(
public name: string,
public age: number
) {}
}
const user = new User("Ada", 36); // same result as the longer version aboveAccess modifiers: public, private, protected
class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
deposit(amount: number): void {
this.balance += amount;
}
getBalance(): number {
return this.balance;
}
}
const account = new BankAccount(100);
account.deposit(50);
account.balance; // Property 'balance' is private and only accessible within class 'BankAccount'public(the default) — accessible from anywhere.private— accessible only inside the class itself.protected— accessible inside the class and any subclass that extends it, but not from outside.
Worth knowing: these are compile-time checks only, enforced by the type checker, not the JavaScript runtime — the compiled output has no real privacy at all (JavaScript's own # private field syntax is the runtime-enforced equivalent, and TypeScript supports it too, but private remains the more common convention in typed codebases).
readonly properties on a class
class User {
readonly id: number;
constructor(id: number) {
this.id = id;
}
}
const user = new User(1);
user.id = 2; // Cannot assign to 'id' because it is a read-only propertyImplementing an interface
A class can declare that it satisfies a given interface, and TypeScript checks that it actually does:
interface Greetable {
name: string;
greet(): string;
}
class Person implements Greetable {
constructor(public name: string) {}
greet(): string {
return `Hi, I'm ${this.name}`;
}
}implements doesn't add any behavior on its own — it's purely a compile-time check that the class provides everything the interface promises. Leaving out greet() here would be a compile error.
Abstract classes
abstract class Shape {
abstract area(): number; // no implementation -- subclasses must provide one
describe(): string {
return `Area: ${this.area()}`;
}
}
class Circle extends Shape {
constructor(private radius: number) {
super();
}
area(): number {
return Math.PI * this.radius ** 2;
}
}An abstract class can't be instantiated directly (new Shape() is a compile error) — it exists to be extended, with abstract methods that every subclass is required to implement.
The next lesson covers type aliases and literal types more fully — the tools for naming a type built from other types, rather than describing a class or interface from scratch.