TypeScript Classes
A practical guide to TypeScript classes, parameter properties, access modifiers, and inheritance mechanisms.
TL;DR
- Declare object blueprints using
classand typed properties. - Use
public,private, andprotectedto control member visibility. - Extend parent classes with
extendsand callsuper()constructors.
Class Syntax
class declarationDeclares an object blueprint with typed property signatures.
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}new instanceInstantiates an object and triggers its constructor execution.
const user = new User('Morgan');
console.log(user.name); // Morganreadonly modifierPrevents reassignment to a property outside initialization.
class Config {
readonly apiKey: string;
constructor(key: string) {
this.apiKey = key;
}
}instance methodDefines functions shared across all class instances.
class Account {
balance: number = 0;
deposit(amount: number): number {
return this.balance += amount;
}
}Parameter Properties
public shorthandDeclares and assigns public instance properties automatically.
class Product {
constructor(
public title: string,
public price: number
) {}
}private shorthandDeclares instance members accessible only within the class.
class Vault {
constructor(private secret: string) {}
reveal(): string {
return this.secret;
}
}readonly shorthandCombines parameter creation with immutability guarantees.
class Coordinate {
constructor(
readonly x: number,
readonly y: number
) {}
}Access Modifiers
public keywordAllows unrestricted read and write access across all scopes.
class Message {
public content: string = '';
}protected keywordRestricts access to the containing class and derived classes.
class BaseService {
protected log(msg: string) {
console.log(`[SYS]: ${msg}`);
}
}# private fieldProvides true ECMAScript runtime encapsulation.
class Counter {
#value = 0;
increment(): number {
return ++this.#value;
}
}Inheritance and Overrides
extends keywordDerives a child class that inherits parent properties.
class Animal {
constructor(public species: string) {}
}
class Dog extends Animal {
bark() { return 'woof'; }
}super() callExecutes parent constructor logic before subclass initialization.
class Employee extends User {
constructor(name: string, public dept: string) {
super(name);
}
}override keywordExplicitly marks methods intended to replace parent methods.
class Logger {
write(msg: string) { console.log(msg); }
}
class JsonLogger extends Logger {
override write(msg: string) {
console.log(JSON.stringify({ msg }));
}
}Static Members
static methodAttaches utility functions directly to the class constructor.
class MathUtil {
static double(n: number): number {
return n * 2;
}
}
MathUtil.double(21); // 42static propertyShares a single variable across all callers and instances.
class InstanceTracker {
static activeSessions: number = 0;
constructor() {
InstanceTracker.activeSessions++;
}
}static blockExecutes complex initialization logic when class evaluates.
class Registry {
static cache: Map<string, string>;
static {
this.cache = new Map();
this.cache.set('v1', 'active');
}
}Tips
- Use parameter properties in
constructorsignatures to declare and assign class fields in a single line. - Mark methods
overridein derived classes to ensure you match the parent class signature accurately.
Warnings
- Remember that the
privatekeyword is compile-time only, so use#private fields for true runtime isolation. - Calling instance methods before
super()in a derived constructor triggers a fatal compile and runtime error.
In Practice
Demonstrates parameter properties, private fields, and inheritance in a banking domain model.
- Declare an abstract base class holding account numbers and balances.
- Use parameter properties to concisely initialize public and protected fields.
- Subclass the base account to add checking overdraft protection.
- Instantiate the derived account and execute typed transactions.
abstract class Account {
constructor(
readonly id: string,
protected bal: number
) {}
abstract debit(amt: number): boolean;
get balance() { return this.bal; }
}
class Savings extends Account {
debit(amt: number) {
if (this.bal < amt) return false;
this.bal -= amt;
return true;
}
}
const acc = new Savings('SA-102', 500);
acc.debit(100);
console.log(`Balance: $${acc.balance}`);FAQ
Abstract classes can include concrete method implementations, constructor logic, and shared state alongside abstract signatures. In contrast, an interface contains only type contracts with zero runtime JavaScript output. Use abstract classes when sharing implementation, and interfaces for contracts.
The private keyword is enforced strictly during TypeScript compilation and gets erased in JavaScript output, meaning properties are still inspectable at runtime. ECMAScript # private fields provide hard runtime privacy that prevents outside inspection even via Object.keys().
Yes, a class can satisfy multiple contracts by separating interfaces with commas after the implements keyword. While TypeScript supports single inheritance with extends, implementing multiple interfaces lets a class fulfill diverse structural roles safely.
class Worker implements Serializable, Loggable {}Choose a static method when the logic operates independently of any specific object instance state, such as factory constructors, parsers, or pure mathematical functions. Static members belong directly to the constructor function itself rather than instance objects.