TypeScript的抽象类

127 阅读3分钟

       看了codewhy的前端TS,下面是我对TS抽象类的相关知识的笔记。

       下面代码作用是计算各种图形面积,通过调用makeArea()函数传入一个图形对象shape,函数内部调用每个图形对象都有的方法getArea()获取图形面积并返回,一共写了两个class用来测试。

       这种写法的弊端在于makeArea()的函数的参数是any类型,这导致非图形类也可以传入,可是非图形类并没有getArea()方法。所以这种写法存在传参错误的分险:

function makeArea(shape: any) {
    return shape.getArea()
}
​
class Rectangle{
    private width: number
    private height: number
​
    constructor(width: number, height: number) {
        this.width = width
        this.height = height
    }
​
    getArea() {
        return this.width * this.height
    }
}
​
class Circle{
    private r: number
​
    constructor(r: number) {
        this.r = r
    }
​
    getArea() {
        return this.r * this.r * 3.14
    }
}
​
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
​
// 由于传入的不是图形对象,没有getArea()方法。又因为参数设置的时any,所以在编译阶段并不会报错,在运行时会报错
const oth = makeArea(12341)

       现在根据上面展现出来的问题对代码进行优化。很明显上面这段代码就是各个类型约束问题,我们可以定义一个图形类的父类Shape,让所有的图形类都继承这个父类,然后对makeArea()函数的参数类型规定为Shape,这样就解决参数类型错误的问题。

​
function makeArea(shape: Shape) {
    return shape.getArea()
}
​
class Shape{
    getArea() {}
}
​
class Rectangle extends Shape{
    private width: number
    private height: number
​
    constructor(width: number, height: number) {
        super()
        this.width = width
        this.height = height
    }
​
    getArea() {
        return this.width * this.height
    }
}
​
class Circle extends Shape{
    private r: number
​
    constructor(r: number) {
        super()
        this.r = r
    }
​
    getArea() {
        return this.r * this.r * 3.14
    }
}
​
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
​
// 将参数类型改为Shape只有下面代码在编辑的时候就会报错了
// const oth = makeArea(12341)

       虽然能够避免其它类型的参数误传,但如果传的是Shape类型的对像还是会有问题const oth1 = makeArea(new Shape())。因为Shape并没有实现getArea()方法,所以这种类型也是无法获取面积的。而且这个Shape类只是作为所有图形的父类,但它并不代表任何形状,所以这个类型的getArea()方法也是实现不了的。这种情况我们应该使用abstract去修饰这个方法,一个正常的方法是必须要有实现的(实现指的就是函数体里面的内容),但是被abstract修饰之后不需要去实现,在这个对象调用这个抽象的方法时也会直接提示这是一个抽象方法。这种抽象方法是必须在抽象类中的,所以Shape这个类也必须要用abstract修饰:

function makeArea(shape: Shape) {
    return shape.getArea()
}
​
abstract class Shape{
    abstract getArea()
}
​
class Rectangle extends Shape{
    private width: number
    private height: number
​
    constructor(width: number, height: number) {
        super()
        this.width = width
        this.height = height
    }
​
    getArea() {
        return this.width * this.height
    }
}
​
class Circle extends Shape{
    private r: number
​
    constructor(r: number) {
        super()
        this.r = r
    }
​
    getArea() {
        return this.r * this.r * 3.14
    }
}
​
const rectangle = new Rectangle(20, 30)
const circle = new Circle(5)
console.log(makeArea(rectangle))
console.log(makeArea(circle))
​
// 将参数类型改为Shape只有下面代码在编辑的时候就会报错了
// const oth = makeArea(12341)// 抽象类在这里会报错
const oth1 = makeArea(new Shape())