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:
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
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
! 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)
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
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
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:
// 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
3. readonly modifier
readonly Properties with modifiers can only be assigned values at the time of declaration or in the constructor:
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
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
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)
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:
100C = 212F
0C = 32F
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:
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
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+)
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
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:
100C = 212F
0C = 32F
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:
100C = 212F
0C = 32F
▶ Example: Static Factory Methods and Readonly Properties
Output:
100C = 212F
0C = 32F
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:
100C = 212F
0C = 32F
❓ FAQ
private truly private at runtime?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; }.private, and when should you use protected?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).this be used 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
- In TypeScript, classes require properties to be declared before they can be used; properties can be initialized at declaration, assigned in the constructor, or
!asserted. - Access modifiers: public (default, accessible from outside the class), protected (accessible to subclasses), private (accessible only within the class)
- Parameter properties simplify the syntax for property declarations and constructor assignments
- Read-only properties can only be initialized at declaration or in the constructor
- Getter/setter methods execute custom logic when reading or writing a property; if there is a getter but no setter, the property is read-only.
- Static members belong to the class itself, not to instances; accessed via
ClassName.member
📝 Exercises
- Basic Problem (Difficulty ⭐): Create a
Rectangleclass (with width and height properties) and implement thegetArea()andgetPerimeter()methods. Simplify the constructor using parameterized properties. - Advanced Problem (Difficulty ⭐⭐): Create a
BankAccountclass—makebalanceprivate, allow operations viadepositandwithdrawmethods, expose the balance as read-only using a getter, and verify that the balance is sufficient before awithdrawoperation. - 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 methodstatic fromArray<T>(items: T[]): Stack<T>to create a stack from the array.