- TypeScript Tutorial
- TypeScript Home
- TypeScript Introduction
- TypeScript Setup
- TypeScript First Program
- TypeScript vs JavaScript
- TypeScript Data Types
- TypeScript Type Inference
- TypeScript Type Annotations
- TypeScript Interfaces
- TypeScript Enums
- TypeScript Type Aliases
- TypeScript Type Assertions
- TypeScript Variables
- TypeScript Functions
- TypeScript Functions
- TypeScript Optional Parameters
- TypeScript Default Parameters
- TypeScript Rest Parameters
- TypeScript Arrow Functions
- Classes and Objects
- Introduction to Classes
- Properties and Methods
- Access Modifiers
- Static Members
- Inheritance
- Abstract Classes
- Interfaces vs Classes
- Advanced Types
- TypeScript Union Types
- TypeScript Intersection Types
- TypeScript Literal Types
- TypeScript Nullable Types
- TypeScript Type Guards
- TypeScript Discriminated Unions
- TypeScript Index Signatures
- TypeScript Generics
- Introduction to Generics
- TypeScript Generic Functions
- TypeScript Generic Classes
- TypeScript Generic Constraints
- TypeScript Modules
- Introduction to Modules
- TypeScript Import and Export
- TypeScript Default Exports
- TypeScript Namespace
- Decorators
- Introduction to Decorators
- TypeScript Class Decorators
- TypeScript Method Decorators
- TypeScript Property Decorators
- TypeScript Parameter Decorators
- Configuration
- TypeScript tsconfig.json File
- TypeScript Compiler Options
- TypeScript Strict Mode
- TypeScript Watch Mode
Introduction to Classes in TypeScript
In modern web development, organizing code is just as important as writing it. Classes in TypeScript act as blueprints for creating objects, allowing you to group data (properties) and behavior (methods) into a single, cohesive unit. While JavaScript introduced classes in ES6, TypeScript takes them to the next level by adding static typing. This means you catch errors during development rather than when your users are running the app, making your codebase more predictable and easier to scale.
Creating a Basic Class
To define a class in TypeScript, you use the class keyword. Unlike plain JavaScript, TypeScript requires you to declare the types of your properties upfront. This allows the compiler to ensure that every instance of your class follows the correct structure.
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
greet(): string {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
}
const person1 = new Person("Alice", 30);
console.log(person1.greet()); // Output: Hello, my name is Alice and I am 30 years old.
In this example:
- Properties:
nameandageare explicitly typed so we don't accidentally assign a number to the name. - The Constructor: This is a special function that runs once when you create a new instance using the
newkeyword. - Methods:
greet()is a function defined inside the class that has access to the instance's data via thethiskeyword.
Class Constructor
The constructor's primary job is to set up the initial state of your object. In TypeScript, you can even use "Parameter Properties" to shorten your code, though we'll stick to the standard way for now to keep things clear.
class Car {
make: string;
model: string;
constructor(make: string, model: string) {
this.make = make;
this.model = model;
}
getDetails(): string {
return `${this.make} ${this.model}`;
}
}
const myCar = new Car("Toyota", "Corolla");
console.log(myCar.getDetails()); // Output: Toyota Corolla
this when referencing class properties. Inside a class, make refers to a local variable, while this.make refers to the class property.
Access Modifiers
One of TypeScript's most powerful features is the ability to control who can see or change your data. We use Access Modifiers to protect the internal state of our objects:
public: The default. Anyone can see and change this property from outside the class.private: Only code inside this specific class can see or change this. It's hidden from the rest of the app.protected: Similar to private, but classes that inherit from this one (subclasses) can also access it.
class Employee {
private id: number;
public name: string;
protected position: string;
constructor(id: number, name: string, position: string) {
this.id = id;
this.name = name;
this.position = position;
}
getEmployeeDetails(): string {
return `ID: ${this.id}, Name: ${this.name}, Position: ${this.position}`;
}
}
const emp = new Employee(1, "John", "Manager");
console.log(emp.name); // Works fine: John
// console.log(emp.id); // Error: 'id' is private and only accessible within class 'Employee'.
private modifier is a "soft" privacy check that happens during compilation. Once the code is turned into JavaScript, the property is technically accessible unless you use the newer ECMAScript private fields (e.g., #id).
Inheritance in Classes
Inheritance allows you to create a specialized version of a class without rewriting all the logic. You use the extends keyword to build a "child" class based on a "parent" class. This is perfect for sharing common logic (like "Animal" traits) while allowing for specific behaviors (like "Dog" barking).
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound(): string {
return `${this.name} makes a sound.`;
}
}
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name); // This triggers the Animal constructor
this.breed = breed;
}
// We are "overriding" the parent method with a specific version
makeSound(): string {
return `${this.name} barks.`;
}
}
const dog = new Dog("Buddy", "Golden Retriever");
console.log(dog.makeSound()); // Output: Buddy barks.
super() in the child constructor before you try to use this. If you don't, TypeScript will throw an error.
Getters and Setters
Sometimes you want to add logic when someone reads or writes to a property for example, validating a price or formatting a name. Getters and setters let you define methods that look like properties to the outside world but run logic behind the scenes.
class BankAccount {
private _balance: number;
constructor(initialBalance: number) {
this._balance = initialBalance;
}
// This acts like a property
get balance(): number {
return this._balance;
}
// This adds validation before changing the value
set deposit(amount: number) {
if (amount > 0) {
this._balance += amount;
} else {
console.error("Deposit must be positive!");
}
}
}
const account = new BankAccount(1000);
console.log(account.balance); // Accessing like a property
account.deposit = 500; // Setting like a property
Static Methods and Properties
Most class members belong to the "instance" (each individual object). However, static members belong to the class itself. You don't need to use the new keyword to access them. They are perfect for utility functions or global configurations.
class MathUtils {
static PI: number = 3.14159;
static calculateCircleArea(radius: number): number {
return this.PI * radius * radius;
}
}
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.calculateCircleArea(10)); // 314.159
In this example, we don't need to create a new MathUtils() because the methods don't rely on any specific instance data.
Summary
Classes in TypeScript are a foundational tool for any developer looking to write clean, organized, and scalable code. By using Access Modifiers, you can protect your data; with Inheritance, you can reuse logic; and with Types, you can ensure your objects always behave exactly as expected. Mastering classes is a major step toward becoming an expert TypeScript developer and building complex applications with confidence.