TypeScript 在 ES6 类的基础上增加了类型系统和多种访问修饰符,让面向对象编程更加严谨和安全。类是 TypeScript 中构建复杂应用的基础单元。

类的基本概念

类是创建对象的模板,封装了数据和操作数据的方法。TypeScript 为类添加了类型注解、访问修饰符、抽象类等特性。

class Person {
  name: string
  age: number

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

  greet(): string {
    return `你好,我是 ${this.name},今年 ${this.age} 岁`
  }
}

const person = new Person("张三", 25)
console.log(person.greet())

上面的代码定义了一个简单的 Person 类,包含两个属性和一个方法。constructor 是构造函数,在创建实例时自动调用。

属性初始化

TypeScript 要求类的属性必须初始化,可以通过构造函数、属性声明或赋值语句来完成。

class User {
  name: string = "匿名"
  age: number
  email: string | undefined

  constructor(age: number) {
    this.age = age
  }
}

const user1 = new User(20)
console.log(user1.name)
console.log(user1.age)
console.log(user1.email)

name 通过属性声明初始化,age 在构造函数中赋值,email 是可选属性可以不初始化。

只读属性

使用 readonly 修饰符可以创建只读属性,只能在声明时或构造函数中赋值。

class Config {
  readonly appName: string = "我的应用"
  readonly version: string

  constructor(version: string) {
    this.version = version
  }
}

const config = new Config("1.0.0")
console.log(config.appName)
console.log(config.version)

尝试在构造函数外修改只读属性会报错,这有助于防止意外修改配置数据。

参数属性

TypeScript 提供了简写语法,可以在构造函数参数上直接声明属性。

class Product {
  constructor(
    public name: string,
    public price: number,
    private stock: number
  ) {}

  getStock(): number {
    return this.stock
  }
}

const product = new Product("手机", 2999, 100)
console.log(product.name)
console.log(product.price)
console.log(product.getStock())

publicprivate 修饰符放在构造函数参数前,TypeScript 会自动创建并初始化对应的属性。

存取器

通过 getset 访问器可以控制属性的读写逻辑,实现数据验证和计算属性。

class Employee {
  private _salary: number = 0

  get salary(): number {
    return this._salary
  }

  set salary(value: number) {
    if (value < 0) {
      console.log("薪水不能为负数")
      return
    }
    this._salary = value
  }
}

const emp = new Employee()
emp.salary = 5000
console.log(emp.salary)
emp.salary = -100

存取器让我们可以在赋值时进行验证,确保数据的有效性。

静态成员

使用 static 关键字定义的成员属于类本身,而不是实例。常用于工具方法和常量。

class MathHelper {
  static PI: number = 3.14159

  static circleArea(radius: number): number {
    return MathHelper.PI * radius * radius
  }
}

console.log(MathHelper.PI)
console.log(MathHelper.circleArea(5))

静态成员通过类名直接访问,不需要创建实例。这在定义工具类和常量时非常有用。

类与接口

类可以实现接口,保证类符合特定的结构契约。一个类可以实现多个接口。

interface IProduct {
  id: number
  name: string
  getPrice(): number
}

interface IStock {
  stock: number
  inStock(): boolean
}

class Phone implements IProduct, IStock {
  id: number
  name: string
  stock: number
  private price: number

  constructor(id: number, name: string, price: number, stock: number) {
    this.id = id
    this.name = name
    this.price = price
    this.stock = stock
  }

  getPrice(): number {
    return this.price
  }

  inStock(): boolean {
    return this.stock > 0
  }
}

const phone = new Phone(1, "iPhone", 6999, 50)
console.log(phone.getPrice())
console.log(phone.inStock())

实现接口的类必须包含接口定义的所有成员,这提供了编译时的类型检查。

抽象类

抽象类不能被实例化,只能被继承。它可以包含抽象方法,由子类实现具体逻辑。

abstract class Shape {
  abstract getArea(): number

  describe(): string {
    return `这是一个形状,面积是 ${this.getArea()}`
  }
}

class Rectangle extends Shape {
  constructor(
    public width: number,
    public height: number
  ) {
    super()
  }

  getArea(): number {
    return this.width * this.height
  }
}

const rect = new Rectangle(10, 20)
console.log(rect.describe())

Shape 是抽象类,定义了抽象方法 getArea,子类 Rectangle 必须实现这个方法。

类作为类型

类本身可以作为类型使用,用于标注变量的类型。

class Point {
  x: number
  y: number

  constructor(x: number, y: number) {
    this.x = x
    this.y = y
  }
}

function printPoint(point: Point): void {
  console.log(`坐标: (${point.x}, ${point.y})`)
}

const p = new Point(10, 20)
printPoint(p)

const obj: Point = { x: 30, y: 40 }
printPoint(obj)

类定义了对象的结构,所以任何符合该结构的对象都可以作为该类型的值。

类表达式

类也可以用表达式的方式定义,适合需要动态创建类或作为返回值的场景。

const Animal = class {
  name: string

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

  speak(): void {
    console.log(`${this.name} 发出声音`)
  }
}

const animal = new Animal("小动物")
animal.speak()

类表达式与类声明功能相同,只是语法形式不同。

泛型类

类可以使用泛型,让类型在实例化时确定,增加代码的复用性。

class Box<T> {
  private content: T

  constructor(content: T) {
    this.content = content
  }

  getContent(): T {
    return this.content
  }

  setContent(content: T): void {
    this.content = content
  }
}

const stringBox = new Box<string>("Hello")
console.log(stringBox.getContent())

const numberBox = new Box<number>(123)
console.log(numberBox.getContent())

Box 类使用泛型 T,可以存储任意类型的数据,同时保持类型安全。

小结

TypeScript 的类在 JavaScript 类的基础上增加了类型系统、访问修饰符、抽象类等特性。这些特性让面向对象编程更加严谨,有助于构建可维护的大型应用。理解类的各种特性是掌握 TypeScript 的关键一步。