TypeScript系列教程八《类》

2021-07-23 16:06:40 浏览数 (1)

TypeScript完全支持ES2015中引入的class关键字。 与其他JavaScript语言特性一样,TypeScript添加了类型注释和其他语法,允许您表达类和其他类型之间的关系。

类的成员


下面是一个空的类:

代码语言:javascript复制
class Point {}

这个类现在毫无用处,现在往这个类里面加点成员

字段

在类上声明字段,编程了可读写的public 属性

代码语言:javascript复制
class Point {
  x: number;
  y: number;
}

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

属性初始化: 类实例化的时候,会初始赋值

代码语言:javascript复制
class Point {
  x = 0;
  y = 0;
}

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

与const、let和var一样,类属性的初始值设定项将用于推断其类型:

代码语言:javascript复制
const pt = new Point();
pt.x = "0";
//Type 'string' is not assignable to type 'number'.

–strictPropertyInitialization

StricPropertyInitialization设置控制类字段是否需要在构造函数中初始化。

正常构建需要初始化:

代码语言:javascript复制
class GoodGreeter {
  name: string;

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

不初始化使用!断言,也不会报错:

代码语言:javascript复制
class OKGreeter {
    // Not initialized, but no error
    name!: string;
  }

readonly

只读属性,不多介绍,只能读取不能赋值。

注意:构造函数内可以赋值

代码语言:javascript复制
class Greeter {
  readonly name: string = "world";

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

  err() {
    this.name = "not ok";
//Cannot assign to 'name' because it is a read-only property.
  }
}
const g = new Greeter();
g.name = "also not ok";
//Cannot assign to 'name' because it is a read-only property.

构造函数

类构造函数与函数非常相似。可以添加带有类型注释、默认值和重载的参数:

代码语言:javascript复制
class Point {
  x: number;
  y: number;

  // Normal signature with defaults
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }
}
代码语言:javascript复制
class Point {
  // Overloads
  constructor(x: number, y: string);
  constructor(s: string);
  constructor(xs: any, y?: any) {
    // TBD
  }
}

super 调用

如果有基类,必须在构造函数中调用super,且在使用this之前

代码语言:javascript复制
class Base {
  k = 4;
}

class Derived extends Base {
  constructor() {
    // Prints a wrong value in ES5; throws exception in ES6
    console.log(this.k);
//'super' must be called before accessing 'this' in the constructor of a derived class.
    super();
  }
}

Methods

在类中函数属性统称为方法

代码语言:javascript复制
class Point {
  x = 10;
  y = 10;

  scale(n: number): void {
    this.x *= n;
    this.y *= n;
  }
}
代码语言:javascript复制
let x: number = 0;

class C {
  x: string = "hello";

  m() {
    // This is trying to modify 'x' from line 1, not the class property
    this.x = "world";
    x = 4 
// Type 'string' is not assignable to type 'number'.
  }
}

Getters / Setters

类也可以有访问器:

代码语言:javascript复制
class C {
  _length = 0;
  get length() {
    return this._length;
  }
  set length(value) {
    this._length = value;
  }
}

注意,没有额外逻辑的字段支持的get/set对在JavaScript中很少有用。如果在get/set操作期间不需要添加额外的逻辑,那么公开公共字段就可以了。

TypeScript对访问器有一些特殊的推理规则:

  • 只有get 没有set ,这个属性自动变成raedonly
  • 如果set 的参数没有明确指出,那么按照get 类型推断
  • Getters and setters必须具有相同的成员可见性(public,private)
代码语言:javascript复制
class Thing {
    _size = 0;

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

    set size(value: string | number | boolean) {
        let num = Number(value);

        // Don't allow NaN, Infinity, etc

        if (!Number.isFinite(num)) {
            this._size = 0;
            return;
        }

        this._size = num;
    }
}

索引签名

类可以声明索引签名;它们的工作方式与其他对象类型的索引签名相同:

代码语言:javascript复制
class MyClass {
  [s: string]: boolean | ((s: string) => boolean);

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

因为索引签名类型还需要捕获方法的类型,所以很难有效地使用这些类型。一般来说,最好将索引数据存储在另一个地方,而不是类实例本身。

类的实现和继承

与其他具有面向对象特性的语言一样,JavaScript中的类可以从基类继承。

implements

一个类可以准守一个或者多个接口去实现它:

代码语言:javascript复制
interface Pingable {
  ping(): void;
}

class Sonar implements Pingable {
  ping() {
    console.log("ping!");
  }
}

class Ball implements Pingable {
//Class 'Ball' incorrectly implements interface 'Pingable'.
  //Property 'ping' is missing in type 'Ball' but required in type 'Pingable'.
  pong() {
    console.log("pong!");
  }
}

类同时可以准守多个接口取实现,例如 class C implements A, B {

可选值不会要求,实现类去实现:

代码语言:javascript复制
interface A {
  x: number;
  y?: number;
}
class C implements A {
  x = 0;
}
const c = new C();
c.y = 10;
Property 'y' does not exist on type 'C'.

extends (继承)

类可以从基类扩展。派生类具有其基类的所有属性和方法,还定义其他成员。

代码语言:javascript复制
class Animal {
  move() {
    console.log("Moving along!");
  }
}

class Dog extends Animal {
  woof(times: number) {
    for (let i = 0; i < times; i  ) {
      console.log("woof!");
    }
  }
}

const d = new Dog();
// Base class method
d.move();
// Derived class method
d.woof(3);

方法重写

子类继承父类之后,可以重写属性和方法

代码语言:javascript复制
class Base {
  greet() {
    console.log("Hello, world!");
  }
}

class Derived extends Base {
  greet(name?: string) {
    if (name === undefined) {
      super.greet();
    } else {
      console.log(`Hello, ${name.toUpperCase()}`);
    }
  }
}

const d = new Derived();
d.greet();
d.greet("reader");

面向对象的特征父类可以指向子类(变量多态):

代码语言:javascript复制
// Alias the derived instance through a base class reference
const b: Base = d;
// No problem
b.greet();

0 人点赞