八、TypeScript 数组

8.1 数组解构

  1. let x: number; let y: number; let z: number;
  2. let five_array = [0,1,2,3,4];
  3. [x,y,z] = five_array;

8.2 数组展开运算符

  1. let two_array = [0, 1];
  2. let five_array = [...two_array, 2, 3, 4];

8.3 数组遍历

  1. let colors: string[] = ["red", "green", "blue"];
  2. for (let i of colors) {
  3. console.log(i);
  4. }

九、TypeScript 对象

9.1 对象解构

  1. let person = {
  2. name: "Semlinker",
  3. gender: "Male",
  4. };
  5. let { name, gender } = person;

9.2 对象展开运算符

  1. let person = {
  2. name: "Semlinker",
  3. gender: "Male",
  4. address: "Xiamen",
  5. };
  6. // 组装对象
  7. let personWithAge = { ...person, age: 33 };
  8. // 获取除了某些项外的其它项
  9. let { name, ...rest } = person;

十、TypeScript 接口

在面向对象语言中,接口是一个很重要的概念,它是对行为的抽象,而具体如何行动需要由类去实现。
TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对「对象的形状(Shape)」进行描述。

10.1 对象的形状

  1. interface Person {
  2. name: string;
  3. age: number;
  4. }
  5. let Semlinker: Person = {
  6. name: "Semlinker",
  7. age: 33,
  8. };

10.2 可选 | 只读属性

  1. interface Person {
  2. readonly name: string;
  3. age?: number;
  4. }

只读属性用于限制只能在对象刚刚创建的时候修改其值。此外 TypeScript 还提供了 ReadonlyArray<T> 类型,它与 Array<T> 相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改。

  1. let a: number[] = [1, 2, 3, 4];
  2. let ro: ReadonlyArray<number> = a;
  3. ro[0] = 12; // error!
  4. ro.push(5); // error!
  5. ro.length = 100; // error!
  6. a = ro; // error!

十一、TypeScript 类

11.1 类的属性与方法

在面向对象语言中,类是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。
在 TypeScript 中,我们可以通过 Class 关键字来定义一个类:

  1. class Greeter {
  2. // 静态属性
  3. static cname: string = "Greeter";
  4. // 成员属性
  5. greeting: string;
  6. // 构造函数 - 执行初始化操作
  7. constructor(message: string) {
  8. this.greeting = message;
  9. }
  10. // 静态方法
  11. static getClassName() {
  12. return "Class name is Greeter";
  13. }
  14. // 成员方法
  15. greet() {
  16. return "Hello, " + this.greeting;
  17. }
  18. }
  19. let greeter = new Greeter("world");

那么成员属性与静态属性,成员方法与静态方法有什么区别呢?这里无需过多解释,我们直接看一下以下编译生成的 ES5 代码:

  1. "use strict";
  2. var Greeter = /** @class */ (function () {
  3. // 构造函数 - 执行初始化操作
  4. function Greeter(message) {
  5. this.greeting = message;
  6. }
  7. // 静态方法
  8. Greeter.getClassName = function () {
  9. return "Class name is Greeter";
  10. };
  11. // 成员方法
  12. Greeter.prototype.greet = function () {
  13. return "Hello, " + this.greeting;
  14. };
  15. // 静态属性
  16. Greeter.cname = "Greeter";
  17. return Greeter;
  18. }());
  19. var greeter = new Greeter("world");

11.2 访问器

在 TypeScript 中,我们可以通过 gettersetter 方法来实现数据的封装和有效性校验,防止出现异常数据。

  1. let passcode = "Hello TypeScript";
  2. class Employee {
  3. private _fullName: string;
  4. get fullName(): string {
  5. return this._fullName;
  6. }
  7. set fullName(newName: string) {
  8. if (passcode && passcode == "Hello TypeScript") {
  9. this._fullName = newName;
  10. } else {
  11. console.log("Error: Unauthorized update of employee!");
  12. }
  13. }
  14. }
  15. let employee = new Employee();
  16. employee.fullName = "Semlinker";
  17. if (employee.fullName) {
  18. console.log(employee.fullName);
  19. }

11.3 类的继承

继承 (Inheritance) 是一种联结类与类的层次模型。指的是一个类(称为子类、子接口)继承另外的一个类(称为父类、父接口)的功能,并可以增加它自己的新功能的能力,继承是类与类或者接口与接口之间最常见的关系。
继承是一种 is-a 关系:
TypeScript 入门教程(八~十一) - 图1
在 TypeScript 中,我们可以通过 extends 关键字来实现继承:

  1. class Animal {
  2. name: string;
  3. constructor(theName: string) {
  4. this.name = theName;
  5. }
  6. move(distanceInMeters: number = 0) {
  7. console.log(`${this.name} moved ${distanceInMeters}m.`);
  8. }
  9. }
  10. class Snake extends Animal {
  11. constructor(name: string) {
  12. super(name);
  13. }
  14. move(distanceInMeters = 5) {
  15. console.log("Slithering...");
  16. super.move(distanceInMeters);
  17. }
  18. }
  19. let sam = new Snake("Sammy the Python");
  20. sam.move();

11.4 ECMAScript 私有字段

在 TypeScript 3.8 版本就开始支持ECMAScript 私有字段,使用方式如下:

  1. class Person {
  2. #name: string;
  3. constructor(name: string) {
  4. this.#name = name;
  5. }
  6. greet() {
  7. console.log(`Hello, my name is ${this.#name}!`);
  8. }
  9. }
  10. let semlinker = new Person("Semlinker");
  11. semlinker.#name;
  12. // ~~~~~
  13. // Property '#name' is not accessible outside class 'Person'
  14. // because it has a private identifier.

与常规属性(甚至使用 private 修饰符声明的属性)不同,私有字段要牢记以下规则:

  • 私有字段以 # 字符开头,有时我们称之为私有名称;
  • 每个私有字段名称都唯一地限定于其包含的类;
  • 不能在私有字段上使用 TypeScript 可访问性修饰符(如 public 或 private);
  • 私有字段不能在包含的类之外访问,甚至不能被检测到。