【TypeScript】Class 成员详解

TypeScript 中的类(class)是对象构建的核心,通过类成员定义属性、构造器和方法,使得代码更加结构化。本文将深入探讨 TypeScript 中类的成员,展示如何定义字段、构造器、方法等内容,帮助你更好地掌握 TypeScript 类的使用。

一、类概述

1. 什么是类?

在面向对象编程中,类是一种模板,通过它可以创建具有相同属性和方法的对象。TypeScript 基于 JavaScript 增强了类的功能,例如提供了更强的类型检查和类成员修饰符,使得代码在开发阶段就能捕捉到更多潜在错误。

2. TypeScript 类的基本定义

以下代码展示了一个最简单的空类:

class Point {
    
    }

这段代码定义了一个名为 Point 的类,但还没有为其添加任何成员,因此在实例化后也不会有任何功能。

二、类成员概述

类成员包括字段、构造器、方法、访问器和索引签名等,这些元素共同定义了类的属性、初始化逻辑和行为。

三、字段 (Fields)

1. 字段声明

字段声明用于定义类中的变量,这些变量会作为实例的属性。TypeScript 中,字段默认是 public 的,也就是说可以在类外直接访问。

class Point {
    
    
  x: number;
  y: number;
}

const pt = new Point();
pt.x = 0;
pt.y = 0;

在这个例子中,Point 类有两个字段 xy,分别定义了坐标点的横纵坐标。在 TypeScript 中,如果不为字段指定类型,则默认类型为 any

2. 字段初始化

字段可以在声明时直接初始化:

class Point {
    
    
  x = 0;
  y = 0;
}

const pt = new Point();
console.log(`${
      
      pt.x}, ${
      
      pt.y}`); // 输出: 0, 0

TypeScript 会自动推断初始化字段的类型。在这个例子中,xy 被推断为 number 类型。如果尝试将 string 赋值给它们,就会产生错误。

3. 严格的属性初始化 (--strictPropertyInitialization)

TypeScript 的 --strictPropertyInitialization 设置会要求所有字段必须在构造函数中被初始化,否则会产生编译错误:

class BadGreeter {
    
    
  name: string; // 错误: 属性 'name' 没有在构造函数中初始化
}

可以通过以下方式修复:

class GoodGreeter {
    
    
  name: string;

  constructor() {
    
    
    this.name = "hello";
  }
}

如果你希望跳过初始化检查,可以使用感叹号 !

class OKGreeter {
    
    
  name!: string;
}

这样,name 字段在未初始化的情况下也不会报错。

4. 只读字段 (readonly)

readonly 字段只能在声明或构造函数中赋值,其他地方修改会报错:

class Greeter {
    
    
  readonly name: string = "world";

  constructor(otherName?: string) {
    
    
    if (otherName !== undefined) {
    
    
      this.name = otherName;
    }
  }
}

在此例中,name 字段在构造函数外无法被修改。

四、构造函数 (Constructors)

构造函数用于实例化类时初始化对象。在 TypeScript 中,可以为构造函数添加类型注解、默认值和重载。

class Point {
    
    
  x: number;
  y: number;

  constructor(x = 0, y = 0) {
    
    
    this.x = x;
    this.y = y;
  }
}

1. 构造函数重载

构造函数支持多种参数签名:

class Point {
    
    
  x: number;
  y: number;

  constructor(x: number, y: number);
  constructor(xy: string);
  constructor(x: string | number, y: number = 0) {
    
    
    // 初始化逻辑
  }
}

2. 父类构造函数的 super 调用

在继承中,子类的构造函数中需要调用 super() 才能访问 this

class Base {
    
    
  k = 4;
}

class Derived extends Base {
    
    
  constructor() {
    
    
    // 错误: 必须先调用 'super()'
    console.log(this.k);
    super();
  }
}

五、方法 (Methods)

类方法用于定义对象的行为,可以与函数一样添加类型注解。

class Point {
    
    
  x = 10;
  y = 10;

  scale(n: number): void {
    
    
    this.x *= n;
    this.y *= n;
  }
}

方法中必须使用 this 访问类的属性和其他方法。

六、访问器 (Getters / Setters)

访问器是获取和设置字段的另一种方式,可以在访问或修改字段时添加逻辑。

class C {
    
    
  _length = 0;

  get length() {
    
    
    return this._length;
  }

  set length(value) {
    
    
    this._length = value;
  }
}

如果访问器中只有 get,则该属性会被推断为只读属性。

不同类型的访问器

自 TypeScript 4.3 起,getset 可以有不同的类型:

class Thing {
    
    
  _size = 0;

  get size(): number {
    
    
    return this._size;
  }

  set size(value: string | number | boolean) {
    
    
    const num = Number(value);
    if (!Number.isFinite(num)) {
    
    
      this._size = 0;
      return;
    }
    this._size = num;
  }
}

七、索引签名 (Index Signatures)

索引签名允许类以类似对象的方式存储键值对:

class MyClass {
    
    
  [s: string]: boolean | ((s: string) => boolean);

  check(s: string) {
    
    
    return this[s] as boolean;
  }
}

索引签名使得类可以存储具有不同类型的键值对,但通常更建议将这些数据存储在类外的对象中。

八、总结

TypeScript 的类提供了丰富的成员类型和控制机制,从而让代码更严谨、更具可读性。通过 readonlystrictPropertyInitializationget/set 等特性,开发者可以编写更加类型安全、结构清晰的面向对象代码。

推荐:


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lph159/article/details/143501876