Typescript 接口、类与继承

    xiaoxiao2022-07-14  220

    一 前言

    TS提供了一系列面向对象的方法,在这里,我们可以像JAVA一样完成一些面向对象的编程,在ES6和TS之前,我们只能利用JS的原型继承以及扩展的继承方法来实现封装与继承,但过程比较繁琐。但TS为我们提供了更为完整的面向对象的写法三要素:封装、继承、与多态。

    在前端的的项目工程中,由于javascript的动态化以及弱类型化,是的编程本身的正确性有所折扣,特别是diamante的压缩中,往往会出现代码逻辑通过,但是语言编译报错,或者执行报错。

    TypeScript的核心原则之一是对变量所具有的结构进行类型检查。通过Ts的类型检查,能够在编写阶段就完成js的编译检查,往往能够缩减很多不必要的麻烦。

    而接口就是其中很重要的一个类型检查。

     

    二 接口

    现在定义一个方法

    function getName(student){ console.log(student.name.padEnd(10, '')); return student.name; } getName('xiao ming')// Uncaught TypeError: Cannot read property 'padEnd' of undefined

    通常我们这样写需要对参数student进行一个判断,有时候为了赶项目可能就忽略了这种判断,那么如果student不是一个Object的实例对象,那么这个函数就会报错。通过接口,我们就能够在编写代码的时候及时的检查到这种错误。

    接口的初步定义

    interface Student { name: string; }

    这个接口表明Student具有一个类型是string的name成员的数据结构;现在改写上面student函数的写法

    function getName(student: Student) { console.log(student.name.padEnd(3, '')); return student.name; } getName('xiao ming'); // 类型“"xiao ming"”的参数不能赋给类型“Student”的参数 interface Student { name: string; }

    可以看到,在调用getName方法的时候,TS抛出了一个类型检查错误:类型“"xiao ming"”的参数不能赋给类型“Student”的参数

    这是因为在调用getName函数的时候,TS会对函数的类型包括参数和返回值进行检查,student参数需要一个name成员,只有完全通过了匹配,TS才会允许安全。

    那如果我们参数没有部分属性或者成员呢,要怎么办呢

    // 不设置可选属性 interface Student { name: string; } let xiaoMing: Student = { name: 'xiao ming', age: 23 } // error 不能将类型“{ name: string; age: number; }”分配给类型“Student”。 对象文字可以只指定已知属性,并且“age”不在类型“Student”中

    下面介绍可选属性和默认属性

    在ES6中,我们可以通过rest参数以及解构赋值为函数参数设置默认参数和可选参数;在TS中也有这些方法:

    // 正确 interface Student { name: string; age?: number; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming' }

    延伸开来,如果我们不知道,也不确定未来人会传什么参数到我们的函数中来怎么办呢?

    TS提供了额外属性检查,同样写法很简单

    // 正确 interface Student { name: string; [p?]: any; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming', age: 18, sex: 'man' }

    这样,我们既确保了我们必须需要的一些成员,同时也不会强迫参数做很大的转变。

    只读属性

    // 正确 interface Student { readonly name: string; [p: string]: any; // 可选成员属性 } let xiaoMing: Student = { name: 'xiao ming', age: 18, sex: 'man' } xiaoMing.name = 'xiao hua' //error Cannot assign to 'name' because it is a read-only property.

    接口在类中的应用--implements

    interface StudentInterface{ name: string; new (name: string): void } class Student implements StudentInterface{ name: string; constructor(name: string) { console.log(this); } }

     三 类与继承

    在ES5中,如果我们需要封装一个对象,需要利用对象的原型链,TS以及ES6后,提出类class的概念。方便我们更好的作封装与继承的工作

    类的声明例如上面的Student;使用方法和JS的构造函数的使用方法一样,需要new关键字;

    let student = new Student('xiao ming');

    其中constructor就是类的构造器,其他包括类的成员与方法:包括实例方法与静态方法。类的实例方法可以用来做为interface进行类型检查。

    属性修饰符

    public|protected|private |static |readonly

    public:公共成员;在任何能够访问到这个类的地方都可以访问这个成员,可继承,可修改。

    class Student { public name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming'); xiaoMing.name;// xiao ming:

    我们可以在子类中访问到name,也可以在实例上访问到name;public可以忽略;如果没有protected和private默认为public成员。

    protected:受保护类型;我们可以在子类中访问到该属性,可继承;该成员属性只能在类和派生类中使用,类外是无法访问的。

    class Student { protected name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming'); xiaoMing.name;// error

    private:即私有属性,无法被继承,类外与派生类中均无法被访问

    class Student { private name = ''; constructor(name: string){ this.name = name; } } class MidStudent implements Student{ constructor(name: string) { this.name = name + ':'; } } let xiaoMing = new MidStudent('xiao ming');// error xiaoMing.name;// error

    static 静态属性,即归属于类的方法,而非实例的方法,例如constructor;需用通过类来访问。

    readonly:只读属性,定义方法和接口的定义方法一样。 

    最新回复(0)