TypeScript的接口

202 阅读3分钟

一. interface描述函数

接口可以在面向对象编程中表示行为的抽象,也可以用来描述对象的形状。接口的作用就是为这些类型命名和为你的代码或第三方代码定义契约。interface接口中不能含有具体的实现逻辑

1.1 对象类型接口

基于interface接口描述对象,这样下次定义同类型参数的时候就能够复用类型

interface IFullName {	// 基于 interface 描述对象
    firstName: string,
    lastName: string
}
// type IFullName = { firstName: string, lastName: string }
const fullName = ({firstName,lastName}:IFullName):string => {
    return firstName + lastName
}

1.2 函数类型接口

通过interface限制函数的参数类型和返回值类型

interface IFullName {
    firstName: string,
    lastName: string
}
interface IFull {
    (obj:IFullName): string
}
// type IFull = (obj:IFullName) => string
const fullName:Full = ({firstName,lastName}) => {
    return firstName + lastName
}

1.3 函数混合类型

基于interface实现函数类型时,在接口中还能定义函数的静态属性

interface ICount {
    (): number
    count: number
}
const fn:ICount = (() => {
    return ++fn.count
}) as ICount	// 函数定义时,会校验 fn 上是否存在count属性,需要断言一下不然会报错

fn.count = 0;

二. interface描述对象

对象接口可以用来描述对象的形状结构,会有许多的特性

2.1 断言

对象实现时额外添加属性会报错,但是我们可以通过断言的方式解决报错

interface IVegetables  {
    color: string,
    taste: string
}
const tomato:IVegetables = {
    color: 'red',
    taste: 'sweet',
    size: 'big'
} as IVegetables	// 断言也需要 IVegetables 中限制的所有属性都必须实现

2.2 接口合并

ts中同名interface接口会被合并

interface IVegetables  {
    color: string,
    taste: string
}
interface IVegetables  {
    size: string
}

const tomato:IVegetables = {	// 同名 IVegetables 接口被合并了
    color: 'red',
    taste: 'sweet',
    size: 'big'
}

2.3 接口的继承

interface定义的接口可以继承

interface IVegetables  {
    color: string,
    taste: string
}
interface ITomato extends IVegetables {
    size: string
}

const tomato:ITomato = {	// ITomato 继承了 IVegetables 接口
    color: 'red',
    taste: 'sweet',
    size: 'big'
}

2.4 可选属性

当不确定有没有某个属性的时候,可以通过?来描述可选属性

interface IVegetables {
    color: string,
    taste: string,
    size?: string
}

const tomato:IVegetables = {
    color: 'red',
    taste: 'sweet',
    size: 'big'		// 可实现,可不实现
}

2.5 任意属性

当我们定义对象时,不能确定后续拓展的属性数量名称

interface IVegetables {
    color: string,
    taste: string,
    [key: string]: any	// 基于这种方式可以无限拓展属性,但是TS没有提示
    // 索引 string 表示可以支持 string,number,symbol类型,js会将索引转成string
}
let p: IVegetables = {
    color: 'red',
    taste: 'sweet',
    size: 'big',
    price: '1$',
    // ... 
}

2.6 可索引接口

可索引接口可以用于标识数组,和数字索引对象

interface IArr {
    [key: number]: any
}
let p: IArr = {
    0:'1',1:'2',3:'3'
}
let arr:IArr = [1,'a',true];

三. interface描述类

3.1 类接口

接口可以被类实现,接口中的方法都是抽象的(没有具体实现,抽象类除外)

interface ISpeakable {
    name: string,
    speak(): void
}
interface IChineseSpeakable {
    speakChinese(): void
}
class Speak implements ISpeakable, IChineseSpeakable { // 类本身需要实现接口中的方法
    speakChinese(): void {
        throw new Error("Method not implemented.");
    }
    name!: string
    speak(): string { // 此方法是原型方法
        return 'xxx'
    }
}
let s = new Speak()

关于类接口中的注意事项

  • 类接口中的方法返回值约束为void时表示不关心返回值

  • 类接口中描述的方法表示当前实例或者原型上的方法

  • 类接口中的所有方法都需要被类实现

3.2 抽象类

abstract声明的抽象类,不能被new,可以被继承的类(属性也可以被abstract标记)

abstract class Animal { 
    abstract name: string  // 没有具体实现,需要子类实现
    eat() {
        console.log('eat')
    }
    abstract drink(): void
}
class Cat extends Animal {
    drink(): void {
        console.log('Method not implemented')
    }
    name: string = 'a'
}
  • abstract中可以放置具体的实现,interface只能放一些抽象的属性和方法,不能有具体实现

3.3 构造函数

interface IClazz {
    new (name:string): any
}
function createClass(target:IClazz,name:string){
    return new target(name);
}
class Animal {
    constructor(public name: string){
        this.name = name;
    }
}
let r = createClass(Animal,'lucky7')