1. 接口继承
● 接口也可以继承
● 还可以使用extends 关键字
interface Person {
name: string
age: 18
}
// Student 接口继承自 Person 接口
interface Student extends Person {
classRoom: number
}
二、类插座
● 为什么要把类socket放在第一位? 因为它非常复杂。
课堂观察与分析
● 我们先写一个简单的类来分析一下
● 我们来看看如何限制一个类
○ 限制调用必须与new关键字一起使用
○ 类上有一个构造函数,需要接受参数并限制返回的实例是什么类型的对象。
○ 我们调用这个类的时候要传递多少个参数,参数是什么类型?
○ 类的原型上有多少个方法?
● 需要这么多维度来限制一个类类型数据
1. 类套接字
● 首先typescript静态类型,我们需要学习一种新的套接字规范,称为类套接字。 类套接字专门用于类。 我们先来看一下。
// 对象接口, 限制实例对象
interface StudentInstance {
name: string
age: number
}
// 类接口, 限制构造器
interface StudentConstructor {
// 构造器的返回值必须要时一个符合 StudentInstance 实例限制的对象
new (name: string, age: number): StudentInstance
}
● 要为类使用套接字,需要使用implements 关键字
class Student implements StudentConstructor {
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
看起来还不错,但是写完之后我发现全错了。
● 分析
○ StudentConstructor接口看起来是一个类socket,但是它可能只限制了new关键字和返回值类型,并不能说它是一个类,它更像是一个函数,所以我们限制不好一类
○ Student类不是函数,而是类,里面的构造函数是构造函数。 然后,当不调用构造函数时,没有实例,因此无法合理添加name和age属性
都是问题,那我们该怎么办呢?
这时候,如果我们想让所有的限制都变得更好,就需要用到鞋厂功能
○ 需要两个插座
○ 受限实例对象
○ 约束构造函数
● 先别急着加TS限制,先用鞋厂模式写类
// 定义工厂函数
// function createStudent( 类, 参数1, 参数2 ) {}
function createStudent( ctro, name, age ) {
return new ctro( name, age )
}
● 也就是说,我们需要将类放入鞋厂函数中来调用
○ 我们的鞋工厂函数需要接受一个类以及该类所需的参数。
○ 在鞋厂函数内进行实例化操作,然后返回
● 接下来我们可以添加套接字限制
// 实例接口, 限制实例对象
interface StudentInstance {
name: string
age: number
sayHi(): void
}
// 类接口, 限制构造器
interface StudentConstructor {
new (name: string, age: number): StudentInstance
}
// 工厂函数
function createStudent( ctro: StudentConstructor, name: string, age: number ): StudentInstance {
return new ctro( name, age )
}
○ 工厂函数的ctro参数必须是满足StudentConstructor接口的类
○ 工厂函数的返回值必须是满足StudentInstance接口的实例对象
○ 通过这两点,限制了类的实例对象的成员。 如果成员多了就不行了。
■ 因为鞋厂函数只能接受这种数据
■ 如果太多,调用鞋厂函数时会出错。
● 最后写作类别
// 实例接口, 限制实例对象
interface StudentInstance {
name: string
age: number
sayHi(): void
}
// 类接口, 限制构造器
interface StudentConstructor {
new (name: string, age: number): StudentInstance
}
// 工厂函数
function createStudent( ctro: StudentConstructor, name: string, age: number ): StudentInstance {
return new ctro( name, age )
}
// 定义类
class Person implements StudentConstructor {
name: string
age: number
constructor (name: string, age: number) {
this.name = name
this.age = age
}
sayHi ():void {}
}
// 开始使用
let s1 = createPerson(Student, '千锋大前端', 10)
console.log(s1)
● 此时,对类的真正限制就完成了
● 确实很麻烦,所以我们在开发过程中对类的限制比较少。
● 因为类本身就是一个限制。
既然我们给类写socket遇到了麻烦,那么我们可以换个思路。使用socket来继承类
3.接口继承类
在常见的面向对象语言中,接口不能继承类,但在 TypeScript 中它可以:
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
为什么 TypeScript 支持套接字继承类?
事实上typescript静态类型,当我们声明类Point时,除了创建一个名为Point的类之外,我们还创建了一个名为Point的类型(实例的类型)。
所以我们可以使用 Point 作为一个类(使用 new Point 创建它的实例):
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
const p = new Point(1, 2);
还可以使用Point作为类型(使用:Point来指示参数的类型):
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
function printPoint(p: Point) {
console.log(p.x, p.y);
}
printPoint(new Point(1, 2));
这个例子实际上相当于:
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface PointInstanceType {
x: number;
y: number;
}
function printPoint(p: PointInstanceType) {
console.log(p.x, p.y);
}
printPoint(new Point(1, 2));
我们在上面的例子中新声明的PointInstanceType类型相当于声明类Point时创建的Point类型。
那么回到Point3d的例子,我们就很容易理解为什么TypeScript支持socket继承类了:
class Point {
x: number;
y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
interface PointInstanceType {
x: number;
y: number;
}
// 等价于 interface Point3d extends PointInstanceType
interface Point3d extends Point {
z: number;
}
let point3d: Point3d = {x: 1, y: 2, z: 3};
当我们声明接口Point3d extends Point时,Point3d实际上继承了类Point的实例类型。
也就是说,可以理解为定义了一个socket Point3d,继承了另一个socket PointInstanceType。
因此,“接口继承类”和“接口继承socket”没有本质区别。
值得注意的是,PointInstanceType 与 Point 相比缺少构造函数方法,因为声明 Point 类时创建的 Point 类型不包含构造函数。 另外,除了不包含构造函数外,也不包含静态属性或静态方法(实例的类型不应包含构造函数、静态属性或静态方法)。
换句话说,声明 Point 类时创建的 Point 类型仅包含其实例属性和实例方法。