TypeScript: TypeScript class (class)

Last updated: 2026-08-26

Classes are an object-oriented syntax feature introduced in JavaScript ES6. TypeScript builds on this by adding type annotations and access control—ensuring that class properties and methods are type-constrained.

1. Basic Syntax of Classes

(1) Property Declarations and Constructors

TypeScript requires that class properties be declared before they can be used—unlike JavaScript:

TYPESCRIPT
class User {
  // Property Declaration(TypeScript Requirements)
  name: string;
  age: number;

  // Constructor
  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }

  // Methods
  greet(): string {
    return `Hello,I am${this.name},This year${this.age} years old`;
  }
}

let user = new User("Charlie", 20);
console.log(user.greet());  // "Hello,I amCharlie,This year20 years old"

(2) Several Ways to Initialize Properties

TYPESCRIPT
class Config {
  // Method 1:Initialize directly upon declaration
  host: string = "localhost";
  port: number = 3000;

  // Method 2:Initialization in the Constructor
  env: string;

  constructor(env: string) {
    this.env = env;
  }

  // Method 3:Assert that it is not empty(!)——You promise to assign a value later.
  data!: string;
}

let cfg = new Config("development");
cfg.data = "some data";  // Create First, Then Assign
🔥 Common Mistake: If a property is neither initialized nor assigned a value in the constructor, TypeScript will throw a "property not initialized" error (in strict mode). You can work around this using the ! assertion, but make sure the property is actually assigned a value.



2. Access Modifiers

TypeScript's three access modifiers control the visibility of properties and methods:

Modifier Within the class Subclass Outside the class
public
protected
private

(1) public (default)

TYPESCRIPT
class Person {
  public name: string;   // public This is the default value.,Optional
  public age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

let p = new Person("Charlie", 20);
console.log(p.name);  // ✅ Accessible from outside the class
p.name = "Diana";      // ✅ Can be modified from outside the class

(2) private

TYPESCRIPT
class BankAccount {
  private balance: number;

  constructor(initialBalance: number) {
    this.balance = initialBalance;
  }

  public deposit(amount: number): void {
    if (amount > 0) this.balance += amount;
  }

  public withdraw(amount: number): boolean {
    if (amount > 0 && amount <= this.balance) {
      this.balance -= amount;
      return true;
    }
    return false;
  }

  public getBalance(): number {
    return this.balance;
  }
}

let account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance());  // 1300
// account.balance;                  // ❌ private The property is not accessible from outside
// account.balance = 99999;          // ❌ private Properties cannot be modified externally

(3) protected

TYPESCRIPT
class Animal {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  protected makeSound(sound: string): void {
    console.log(`${this.name}:${sound}`);
  }
}

class Dog extends Animal {
  constructor(name: string) {
    super(name);
  }

  public bark(): void {
    this.makeSound("Woof!");  // ✅ Subclasses can access protected Methods
    // console.log(this.name);  // ✅ Subclasses can access protected Properties
  }
}

let dog = new Dog("Wangcai");
dog.bark();           // "Wangcai:Woof!"
// dog.name;           // ❌ protected The property is not accessible from outside
// dog.makeSound("Howl"); // ❌ protected This method cannot be called from outside the class.

(4) Shorthand for Constructor Parameters

TypeScript provides parameter properties—by adding modifiers before constructor parameters, it automatically declares and initializes properties:

TYPESCRIPT
// Complete Syntax
class User1 {
  public name: string;
  private age: number;

  constructor(name: string, age: number) {
    this.name = name;
    this.age = age;
  }
}

// Abbreviation——The effect is exactly the same
class User2 {
  constructor(
    public name: string,
    private age: number
  ) {}
}

let u = new User2("Charlie", 20);
console.log(u.name);    // ✅ public
// console.log(u.age);  // ❌ private
💡 Tip: Parameter properties make the code more concise, but readability decreases when there are too many properties. For three or fewer properties, use the shorthand notation; for more than three, explicitly declare them.



3. readonly modifier

readonly Properties with modifiers can only be assigned values at the time of declaration or in the constructor:

TYPESCRIPT
class Circle {
  readonly radius: number;

  constructor(radius: number) {
    this.radius = radius;  // ✅ You can assign values in the constructor
  }

  get area(): number {
    return Math.PI * this.radius ** 2;
  }
}

let circle = new Circle(5);
console.log(circle.area);     // 78.54
// circle.radius = 10;        // ❌ readonly Properties cannot be modified

(1) readonly + parameter properties

TYPESCRIPT
class Config {
  constructor(
    readonly host: string,
    readonly port: number
  ) {}
}

let cfg = new Config("localhost", 3000);
console.log(`${cfg.host}:${cfg.port}`);  // "localhost:3000"
// cfg.host = "other";  // ❌ readonly


4. Accessors (getters / setters)

Accessors allow you to execute custom logic when reading or writing properties:

(1) Basic Syntax

TYPESCRIPT
class Employee {
  private _salary: number = 0;

  // getter——Execute on read
  get salary(): number {
    return this._salary;
  }

  // setter——Perform validation during assignment
  set salary(value: number) {
    if (value < 0) {
      throw new Error("Salaries cannot be negative.");
    }
    this._salary = value;
  }
}

let emp = new Employee();
emp.salary = 8000;       // Call setter
console.log(emp.salary);  // Call getter → 8000
// emp.salary = -100;     // ❌ Throw an error

(2) Read-only properties (with a getter but no setter)

TYPESCRIPT
class User {
  constructor(
    private firstName: string,
    private lastName: string
  ) {}

  get fullName(): string {
    return `${this.firstName} ${this.lastName}`;
  }
  // None setter → fullName It is read-only.
}

let user = new User("San", "Zhang");
console.log(user.fullName);  // "San Zhang"
// user.fullName = "Si Li";  // ❌ None setter

▶ Example: Temperature Converter

Output:

TEXT 📖 Display only
100C = 212F
0C = 32F
TYPESCRIPT
class Temperature {
  private _celsius: number = 0;

  constructor(celsius: number) {
    this._celsius = celsius;
  }

  get celsius(): number {
    return this._celsius;
  }

  set celsius(value: number) {
    if (value < -273.15) {
      throw new Error("The temperature must not fall below absolute zero.(-273.15°C)");
    }
    this._celsius = value;
  }

  get fahrenheit(): number {
    return this._celsius * 9 / 5 + 32;
  }

  set fahrenheit(value: number) {
    this.celsius = (value - 32) * 5 / 9;  // Reuse celsius Verification of
  }
}

let temp = new Temperature(100);
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`);  // "100°C = 212°F"

temp.fahrenheit = 32;
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`);  // "0°C = 32°F"

Output:

TEXT 📖 Display only
100°C = 212°F
0°C = 32°F


5. Static Members

static Modified properties and methods belong to the class itself, not to the instance:

(1) Static Properties and Methods

TYPESCRIPT
class MathUtils {
  static PI: number = 3.14159;

  static circleArea(radius: number): number {
    return MathUtils.PI * radius ** 2;
  }

  static clamp(value: number, min: number, max: number): number {
    return Math.min(Math.max(value, min), max);
  }
}

// No need to create an instance,Call directly using the class name
console.log(MathUtils.PI);              // 3.14159
console.log(MathUtils.circleArea(5));   // 78.53975
console.log(MathUtils.clamp(150, 0, 100));  // 100

(2) Static Blocks (TypeScript 5.0 / ES2022+)

TYPESCRIPT
class Config {
  static host: string;
  static port: number;

  // Static Initialization Block
  static {
    Config.host = process.env.HOST ?? "localhost";
    Config.port = Number(process.env.PORT) || 3000;
  }
}

(3) The Difference Between Static Members and Instance Members

TYPESCRIPT
class Counter {
  static totalCount: number = 0;   // Shared by all instances
  instanceCount: number = 0;       // Each instance is independent

  increment(): void {
    Counter.totalCount++;
    this.instanceCount++;
  }
}

let c1 = new Counter();
let c2 = new Counter();

c1.increment();
c1.increment();
c2.increment();

console.log(`Examples1:${c1.instanceCount}`);  // 2
console.log(`Examples2:${c2.instanceCount}`);  // 1
console.log(`Total:${Counter.totalCount}`); // 3

▶ Example: Class with Access Modifiers and Constructor Shorthand

Output:

TEXT 📖 Display only
100C = 212F
0C = 32F
TYPESCRIPT
class Article {
  constructor(
    readonly id: number,
    public title: string,
    private _views: number = 0
  ) {}

  get views(): number {
    return this._views;
  }

  incrementViews(): void {
    this._views++;
  }

  toString(): string {
    return `[${this.id}] ${this.title} (${this.views} views)`;
  }
}

let post = new Article(1, "Hello TypeScript");
post.incrementViews();
post.incrementViews();
console.log(post.toString());  // "[1] Hello TypeScript (2 views)"
// post._views;  // ❌ private — cannot access from outside

Output:

TEXT 📖 Display only
100C = 212F
0C = 32F

▶ Example: Static Factory Methods and Readonly Properties

Output:

TEXT 📖 Display only
100C = 212F
0C = 32F
TYPESCRIPT
class Point {
  constructor(
    public readonly x: number,
    public readonly y: number
  ) {}

  static origin: Point = new Point(0, 0);

  static fromAngle(angle: number, distance: number): Point {
    return new Point(
      Math.round(distance * Math.cos(angle)),
      Math.round(distance * Math.sin(angle))
    );
  }

  distanceTo(other: Point): number {
    return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
  }
}

let p = Point.fromAngle(Math.PI / 4, 10);
console.log(`(${p.x}, ${p.y})`);                // "(7, 7)"
console.log(p.distanceTo(Point.origin));        // "~10"

Output:

TEXT 📖 Display only
100C = 212F
0C = 32F

❓ FAQ

Q Is private truly private at runtime?
A No. TypeScript’s private is only a compile-time check—private properties are still accessible in the compiled JavaScript code. The #private syntax in ES2022 (private fields) is what provides true runtime privacy. TypeScript also supports #private: class C { #secret = 1; }.
Q When should you use private, and when should you use protected?
A private is used for internal implementation details that “only the class itself needs”; protected is used for members that “subclasses may also need to access or override.” If you’re unsure, start with private—you can always change it to protected later if needed (it’s safer to be more permissive than more restrictive).
Q What is the difference between getters/setters and regular methods?
A Getter/setter methods make reading and writing properties appear as if they were being accessed directly (YIJIAN0PH), but they execute custom logic behind the scenes. Regular methods require explicit calls (YIJIAN1PH). It is recommended to use getters/setters for externally exposed properties (to perform validation or compute properties), and regular methods for internal implementation.
Q Can this be used in static methods?
A In static methods, this refers to the class itself (not an instance). In static create() { return new this(); }, this is equal to the current class. However, this may be lost in arrow functions or callbacks—it is recommended to use the class name instead of this in static methods.

📖 Summary

📝 Exercises

  1. Basic Problem (Difficulty ⭐): Create a Rectangle class (with width and height properties) and implement the getArea() and getPerimeter() methods. Simplify the constructor using parameterized properties.
  2. Advanced Problem (Difficulty ⭐⭐): Create a BankAccount class—make balance private, allow operations via deposit and withdraw methods, expose the balance as read-only using a getter, and verify that the balance is sufficient before a withdraw operation.
  3. Challenge (Difficulty: ⭐⭐⭐): Implement a generic class Stack<T>—store data in a private array, provide push, pop, peek, and size methods, implement the size property (read-only) using getters, and use a static method static fromArray<T>(items: T[]): Stack<T> to create a stack from the array.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏