TypeScript 面向对象(二)

633 阅读3分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情

接口

约束对象结构

之前我们学了类型注解,直接在对象名后写类型注解的坏处:

1、代码结构不简洁。

2、无法复用类型注解。例如我们看以下代码:

let p1: {
    name: string
    age: number
    sayHello: () => void
} = {
    name: '孙悟空',
    age: 18,
    sayHello() {
        console.log("Hello 悟空");
    }
}
let p2: {
    name: string
    age: number
    sayHello: () => void
} = {
    name: '八戒',
    age: 16,
    sayHello() {
        console.log("Hello 八戒");
    }
}

这种情况就用到了接口,接口:为对象的类型注解命名,并为你的代码建立契约来约束对象的结构。我们使用接口修改以上代码:

interface IUser {
    name: string
    //这个属性可有可无
    age?: number
    sayHello: () => void
}

let p1: IUser = {
    name: '孙悟空',
    sayHello() {
        console.log("Hello 悟空");
    }
}
let p2: IUser = {
    name: '八戒',
    age: 16,
    sayHello() {
        console.log("Hello 八戒");
    }
}
	console.log(p2.name)
    p2.name="沙僧"
    console.log(p2.name)

在这里插入图片描述

现在的属性是可读可写的,如果不想修改可以增加 readonly

interface IUser {
        readonly name: string
        age: number
        sayHello: () => void
}

再尝试修改 name 属性就会报错: 在这里插入图片描述

接口在类中的作用

其实接口和抽象类非常相似,区别有两个:

1、抽象类能有抽象方法也可以有普通方法,而接口中的方法都是抽象方法

2、抽象类使用 extends 继承,接口使用implements实现

(function () {
    /********* 例子 1 *********/
    //先演示描述一个对象的类型
    type myType = {
        name: string,
        age: number
    };

    const obj: myType = {
        name: "张三",
        age: 23
    };

    //接口在类中的作用就是用来定义一个类的结构
    //用来定义一个类中应该有哪些类型和方法
    //也可以当作类型声明来使用,和上边的作用一样
    interface myInterface {
        name: string;
        age: number;
    }

    //可以声明相同的接口
    interface myInterface {
        gender: string;
    }

    //那么这个obj2里边就是上边接口的和
    const obj2: myInterface = {
        name: "李四",
        age: 24,
        gender: "男"
    }

    /********* 例子 2 *********/
    //接口可以在定义类的时候限制类的结构
    // 接口中所有属性都不能有实际值
    //接口只定义对象的结构,而不考虑实际值
    //在接口中所有的方法都是抽象方法
    interface myInter {
        name: string;

        sayHello(): void
    }
    //定义一个类实现一个接口
    class MyClass implements myInter{
        name: string;

        constructor(name:string) {
            this.name = name;
        }

        sayHello(): void {
            console.log("hello")
        }
    }
})();

接口也可以继承其他接口,使用关键字 extends

函数类型

定义一个接口,用来做为某个函数的类型使用

interface ISearchFunc {
        // 定义一个调用签名
        (source: string, subString: string): boolean
    }

    // 定义一个函数,类型就是上边的接口
    const searchString: ISearchFunc = function (source: string, subString: string): boolean {
   		 // 在source中查找substring
        return source.search(subString) > -1
    }

    console.log(searchString('hello,world', 'hello'))//true

属性的封装

(function () {
    //定义一个表示人的类
    class Person {
        //TS可以在属性前添加属性修饰符
        //public(共有)
        //private(私有)可以添加方法,get、set方法
        //protect 只能在当前类和当前类的子类中使用
        public name: string;
        private age:number;

        constructor(name: string,age:number) {
            this.name = name;
            this.age = age;
        }

        getAge(){
            return this.age;
        }

        setAge(age:number){
            //判断年龄是否合法
            if(age>=0){
                this.age = age;
            }
        }
    }

    const person = new Person("孙悟空",18);
    //现在的属性都是在对象中设置的,属性可以被任意修改,这样非常不安全
    person.name = "八戒";
    //所以可以把属性改为private,然后增加get、set方法
    person.setAge(20);
    console.log(person);
})();

TS 中设置 getter 方法的方式

(function () {
    class Person {
        private _name: string;
        private _age: number;

        constructor(_name: string, _age: number) {
            this._name = _name;
            this._age = _age;
        }

        //TS 中getter方法
        get name() {
            return this._name
        }

        set name(name: string) {
            this._name = name;
        }

        get age() {
            return this._age;
        }

        set age(age: number) {
            if (age > 0) {
                this._age = age;
            }
        }
    }

    const person = new Person("孙悟空", 18);
    person.name = "八戒";
    person.age = -22;
    console.log(person)
})();

在这里插入图片描述

可以将属性直接定义在构造函数中

(function () {
    class Person {
        //可以将属性直接定义在构造函数中
        constructor(public name: string, public age: number) {
        }
    }

    const person = new Person("孙悟空", 18);
    console.log(person.name);//打印出孙悟空
})();