typescript入门(四)接口

193 阅读5分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」。

1. 接口的作用

接口的作用就是为类型命名和为你的代码或第三方代码定义契约。

2. 写法

写法: interface 接口名{}

interface Obj {
    name: string;
}
let obj1:Obj = {
    name: 'Amy'
}

注意:

  • 当obj1为字面量时,是不能有除了name属性的其他属性的。 以下写法是错误的:
let obj1:Obj = {
    name: 'Amy',
    age: 12 // 报错
}
  • 当obj1为obj2对象赋值时,允许有其他属性:
let obj2 = {
    name:'John',
    age: 12
}
let obj1: Obj = obj2;

3. 可选属性

对于不一定要传入的属性可设置为可选属性,仅需在变量名后添加问号。

interface Obj {
    name: string;
    age?: number;
}
let obj1:Obj = {
    name: 'Amy'
}

上例中age属性设置为可选属性,所以obj1中可以不传入age属性

4. 只读属性

只赋值后不允许属性修改,可使用只读属性,仅需在变量名前添加readonly关键字。

interface Obj {
    readonly name: string;
}
let obj1:Obj = {
    name: 'Amy'
}
obj1.name = 'qq'; // 报错

上例中name属性设置为只读属性,所以值不能被修改。

注意:判断该用readonly还是const的方法,是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const,若做为属性则使用readonly

5.函数类型

接口除了描述带有属性的普通对象外,也可以描述函数类型。

例:

interface MsgFun {
    (name:string, age: number):string;
}
let myMsgFun: MsgFun;
myMsgFun = function(name:string, age: number) {
    return `my name is ${name},I am ${age}`
}

上例中定义了函数接口MsgFun,函数接收两个参数nameage,返回值为string。 给变量myMsgFun定义为MsgFun类型,myMsgFun赋值时就应该按MsgFun类型的规范设置。

注意

  1. 对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配,但类型应该对应相同。

上例中,也可将myMsgFun赋值为第一个参数为work(work必须与MsgFun中第一个参数name的类型一致),第二个参数为age的函数:

myMsgFun = function(work:string, age:number) {
    return `my work is ${work},I am ${age}`
}
  1. 函数参数的数量也可少于接口里定义的参数数量。

上例中,可将myMsgFun赋值为参数数量只有0或1的函数。

举个例子:

myMsgFun = function() {
    return `qqq`
}

6.可索引类型

可索引类型的接口具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型。 TypeScript支持两种索引签名:字符串和数字。

  1. 数字类型的索引签名
interface StrArray {
    [num: number]: string
}
let strArr: StrArray;
strArr = ['qq','ww']
let str1 = strArr[0];
console.log(str1); // qq

上例中设置StrArray接口的索引签名为数字。给strArr变量定义为StrArray类型,则赋值时应按照索引为数字的形式赋值。

注意:当使用 number来索引时,JavaScript会将它转换成string然后再去索引对象。

  1. 字符串类型的索引签名
interface StrIndex {
    [index: string] : string
}
let strIndex:StrIndex;
strIndex = {
    a:'q'
}
console.log(strIndex.a);

7、类类型

TypeScript也能用类类型的接口来明确的强制一个类去符合某种契约。 举个例子:

interface Animal3 {
    type: string; 
}
class Fish implements Animal3 {
    type: string;
    constructor(){
        this.type = 'fish';
    }
}

注意

  • 类实现接口,必须实现接口中的所有属性和方法,类也可以定义自己的属性。
  • 接口只能约束类的公有成员,不能约束其private和protected成员。
  • 接口不能约束类的构造函数。

8、继承接口

接口和类一样,也可以继承,从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。

interface Animal4 {
    type: string;
}
interface catType extends Animal4 {
    typeName: string;
}
let cat1 = <catType>{};
cat1.type = "orangeCat";
cat1.typeName = "cat";

上例中,定义了catType接口继承Animal4接口,定义cat1变量断言为catType类型,cat1上存在typetypeName两个属性,若添加其他属性则会报错

注意:一个接口可以继承多个接口,创建出多个接口的合成接口。

9、混合类型

当希望接口具有多种类型时,可设置为混合类型。

类型包括:对象类型、函数类型、类类型。

以下例子中,一个对象可以同时做为函数和对象使用,并带有额外的属性。

interface Counter {
    (start: number): string;
    interval: number;
    reset(): void;
}

function getCounter(): Counter {
    let counter = <Counter>function (start: number) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}

let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;

上例中创建了一个Counter接口,既是一个函数接口,也是一个对象接口。 定义getCounter()为Counter类型,counter为Counter类型。

10、接口继承类

  • 当接口继承了一个类类型时,它会继承类的成员但不包括其实现。 就好像接口声明了所有类中存在的成员,但并没有提供具体实现一样。
  • 接口会继承到类的private和protected成员。 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时,这个接口类型只能被这个类或其子类所实现(implement)。
class Control {
    private state: string;
    constructor(state:string) {
        this.state = state;
    }
}

interface SelectableControl extends Control {
    select(): void;
}

class SubControl extends Control implements SelectableControl {
    select() {
        console.log('select');
    }
}

上例中

  • 设置Control类拥有私有属性state
  • 接口SelectableControl继承自Control类,内设select方法。
  • SubControl类继承Control类,也拥有了父类的私有属性state,并实现接口SelectableControl,必须要含有select方法,否则报错。

11、类与接口的关系图

image.png