Classes in TypeScript
Angular components, services, directives, and pipes are all TypeScript classes. Understanding classes is essential for Angular development.
Basic Class
class Animal {
name: string;
sound: string;
constructor(name: string, sound: string) {
this.name = name;
this.sound = sound;
}
speak(): string {
return `${this.name} says ${this.sound}!`;
}
}
const dog = new Animal('Dog', 'Woof');
console.log(dog.speak()); // "Dog says Woof!"Parameter Properties (Shorthand)
TypeScript lets you declare and initialize properties directly in the constructor:
class User {
constructor(
public name: string,
public email: string,
private password: string,
) {}
getProfile() {
return { name: this.name, email: this.email };
}
}
const user = new User('Alice', 'alice@test.com', 'secret123');
console.log(user.name); // 'Alice' — accessible
// console.log(user.password); // Error: 'password' is privateAccess Modifiers
| Modifier | Accessible From | Angular Usage |
|---|---|---|
public | Everywhere | Template-bound properties |
private | Same class only | Internal logic |
protected | Same class + subclasses | Base class methods |
readonly | Read-only after init | Constants, injected services |
class BankAccount {
public owner: string;
private balance: number;
protected accountType: string;
readonly id: string;
constructor(owner: string, initialBalance: number) {
this.owner = owner;
this.balance = initialBalance;
this.accountType = 'checking';
this.id = crypto.randomUUID();
}
public deposit(amount: number): void {
this.balance += amount;
}
public getBalance(): number {
return this.balance;
}
}Angular Tip: Properties bound to the template in Angular must be public (or have no modifier, which defaults to public).
Inheritance
class Shape {
constructor(public color: string) {}
describe(): string {
return `A ${this.color} shape`;
}
}
class Circle extends Shape {
constructor(color: string, public radius: number) {
super(color); // Call parent constructor
}
area(): number {
return Math.PI * this.radius ** 2;
}
// Override parent method
override describe(): string {
return `A ${this.color} circle with radius ${this.radius}`;
}
}
const circle = new Circle('red', 5);
console.log(circle.describe()); // "A red circle with radius 5"
console.log(circle.area()); // 78.539...Abstract Classes
Abstract classes cannot be instantiated directly — they serve as base classes:
abstract class BaseComponent {
abstract title: string;
abstract render(): string;
log(): void {
console.log(`Rendering: ${this.title}`);
}
}
class HeaderComponent extends BaseComponent {
title = 'Site Header';
render(): string {
return `<header>${this.title}</header>`;
}
}
// const base = new BaseComponent(); // Error: cannot instantiate abstract class
const header = new HeaderComponent();
header.log(); // "Rendering: Site Header"
header.render(); // "<header>Site Header</header>"Implementing Interfaces
Classes can implement interfaces to guarantee they conform to a contract:
interface Serializable {
toJSON(): string;
}
interface Loggable {
log(): void;
}
class Product implements Serializable, Loggable {
constructor(
public name: string,
public price: number,
) {}
toJSON(): string {
return JSON.stringify({ name: this.name, price: this.price });
}
log(): void {
console.log(`Product: ${this.name} — $${this.price}`);
}
}Getters and Setters
class Temperature {
private _celsius: number;
constructor(celsius: number) {
this._celsius = celsius;
}
get celsius(): number {
return this._celsius;
}
set celsius(value: number) {
if (value < -273.15) {
throw new Error('Temperature below absolute zero!');
}
this._celsius = value;
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
}
const temp = new Temperature(100);
console.log(temp.fahrenheit); // 212
temp.celsius = 0;
console.log(temp.fahrenheit); // 32Understanding Decorators
Decorators are special functions that modify classes, methods, or properties. Angular relies heavily on decorators.
How Decorators Work
A decorator is a function that receives the target it decorates and can modify it:
// A simple class decorator
function LogClass(constructor: Function) {
console.log(`Class created: ${constructor.name}`);
}
@LogClass
class MyService {
// When this class is loaded, the console logs:
// "Class created: MyService"
}Angular's Built-in Decorators
| Decorator | Target | Purpose |
|---|---|---|
@Component() | Class | Defines a component |
@Injectable() | Class | Marks a service for DI |
@Directive() | Class | Defines a directive |
@Pipe() | Class | Defines a pipe |
@Input() | Property | Accepts data from parent |
@Output() | Property | Emits events to parent |
@ViewChild() | Property | References a child element |
@HostListener() | Method | Listens to host element events |
Decorator Factories (with Parameters)
Angular decorators are factories — they return the actual decorator:
// @Component is a factory
@Component({
selector: 'app-user-card',
standalone: true,
templateUrl: './user-card.component.html',
styleUrl: './user-card.component.css',
})
export class UserCardComponent {
// Component logic
}Property Decorators in Angular
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-product-card',
standalone: true,
template: `
<div class="card">
<h3>{{ product.name }}</h3>
<p>{{ product.price | currency }}</p>
<button (click)="onAddToCart()">Add to Cart</button>
</div>
`,
})
export class ProductCardComponent {
@Input() product!: Product; // Input from parent
@Output() addToCart = new EventEmitter<Product>(); // Output to parent
onAddToCart() {
this.addToCart.emit(this.product);
}
}Practical Example: Angular Component Class
Here's a complete example combining classes, decorators, and TypeScript features:
import { Component, OnInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
interface Task {
id: number;
title: string;
completed: boolean;
}
@Component({
selector: 'app-task-list',
standalone: true,
imports: [CommonModule],
template: `
<h2>Tasks ({{ incompleteTasks.length }} remaining)</h2>
<ul>
@for (task of tasks; track task.id) {
<li [class.done]="task.completed">
<input type="checkbox"
[checked]="task.completed"
(change)="toggle(task)" />
{{ task.title }}
</li>
}
</ul>
`,
styles: [`.done { text-decoration: line-through; opacity: 0.6; }`],
})
export class TaskListComponent implements OnInit {
tasks: Task[] = [];
get incompleteTasks(): Task[] {
return this.tasks.filter(t => !t.completed);
}
ngOnInit() {
this.tasks = [
{ id: 1, title: 'Learn TypeScript', completed: true },
{ id: 2, title: 'Build Angular app', completed: false },
{ id: 3, title: 'Deploy to production', completed: false },
];
}
toggle(task: Task) {
task.completed = !task.completed;
}
}Next Steps
Now that you understand TypeScript classes and decorators, you're ready to dive into Angular components — the core building blocks of every Angular application.