首页 > 技术文章 > Typescript Interface 接口

ltfxy 2020-10-12 00:48 原文

1 关于接口

对于值的类型检查是typescript的核心设计原则,而typescript接口的责任就是命名这些值的类型。
因此,可以说接口是typescript核心设计原则————类型检查的实现方式。

2 接口初探

用一个小demo来看看JavaScript和typescript的特点

function fnPrintObj(obj: Object) {

    console.log(obj)

}

interface IObj {

    key: string

}
function fnPrintObj2(obj: IObj) {

    console.log(obj)

}
fnPrintObj({ key: 'island' })
fnPrintObj2({ key: "island" })
fnPrintObj2({ name: "island" }) // error

在fnPrintObj中,只要是对象类型都可以被打印
在fnPrintObj2中,只有数据结构契合接口IObj的才可以被打印

3 可选属性

然而,实际应用中,我们并不要求函数形参必须具有接口中所有的属性类型。
因此,可选属性是非常必要的。

interface someI{
    name?:string
    age?:Number
    color?:string

}
function fnPrintObj3(obj:someI){

    console.log(obj)

}

fnPrintObj3({name:"island", age:12, color:"red"})
fnPrintObj3({color:"red"})

4 只读属性

有些属性只能在对象刚刚创建的时候修改其值,可用到此特性。
和const不同,const常作为常量使用,作用者是变量
readonly作为属性使用,作用者是对象属性

interface appleI{

    readonly weight : number
    readonly radius ?: number

}
function fnGetApple(obj:appleI){

    return obj

}
let apple = fnGetApple({weight:100, radius:50})
let apple2 : appleI = {weight:100}
// apple.weight = 200 // error
// apple2.weight = 300 // error

let appleList : ReadonlyArray<appleI> = [apple, apple2]
// appleList.push(apple2) error
console.log(appleList)

5 函数类型

接口除了能够描述带有属性的对象类型之外,也可以描述函数类型
定义函数类型时,只需要定义形参列表和返回值即可

interface findI {

    // 形参列表 : 返回值类型
    (source: string, item: string): boolean

}
let myFind: findI
myFind = function (source: string, item: string) {

    return source.search(item) > -1

}
console.log(myFind("heihei", 'ei')) // true

6 指定索引类型

可索引的类型 指定索引值的类型

interface StringArray {

    [index: number]: string;

}

let myArray : StringArray; 
myArray = ["s1", "s2"]
let indexStr : string = myArray[0]
// console.log(indexStr)

7 类和接口

与Java或C#一样,Typescript也能够用它来明确的强制一个类去遵守某种契约
与Java不同的是,Typescript的类实现接口,不存在方法的重载,全部是方法的重写

当一个类实现了一个接口,只有实例部分会被检查,静态部分(比如构造函数)不会被检查

interface ClockInterface{

    currentTime:Date

}
class Clock implements ClockInterface{

    // 只检查实例部分,构造函数属于静态部分,不会被检查
    constructor(h:number, m:number){}
    // 实例部分会被检查

    currentTime:Date

}

8 继承接口

和类一样,接口也可以相互继承。
接口之间的继承使得一个接口可以从另一个接口里复制成员,便于抽离和处理可重用的模块。

interface Eye {

    eyeColor: string

}

interface Nose {

    noseSize: string

}

interface Person extends Eye, Nose {

    height: number
    weight: number

}

class Chinese implements Person {

    constructor(h:number, w:number, c:string, s:string){
        this.height = h
        this.weight = w
        this.eyeColor = c
        this.noseSize = s
    }

    height: number
    weight: number

    eyeColor: string

    noseSize: string

    introduceMe(){
        console.log("我的信息:", this.height, this.weight, this.eyeColor, this.noseSize)
    }

}
let dragon = new Chinese(170, 60, "blue", "middle")
dragon.introduceMe()

let person = <Person>{}
person.eyeColor = 'blue'
person.noseSize = 'big'
person.height = 170
person.weight = 60
// console.log(person) // { color: 'blue', size: 'big', height: 170, weight: 60 }

混合类型

在JS中,函数也是一种特殊类型的对象
因此,在TS接口中,函数和对象的类型都可以被同一个接口作用

interface Counter {

    (start: number): string
    interval: number
    reset(): void

}

// 必须返回一个对象 等价于 let obj : Counter = <Counter>{}
function getCounter(): Counter {

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

}
let counter = getCounter()
counter(10)
counter.reset()
counter.interval = 5.0
console.log(counter) // [Function: counter] { interval: 5, reset: [Function] }

let obj : Counter = <Counter>{

    interval:1000,
    reset:()=>{}

}
console.log(obj) //{ interval: 1000, reset: [Function: reset] }

接口继承类

当接口继承了一个类,它会继承类的成员,但接口中继承过来的成员是仅有定义而没有实现的
需要说明的是,如果一个接口继承了一个拥有private或protected成员的类时,此接口只能有此类的子类所实现

class Control {
    private state: any
    private state2 = 2
    public state3: any
    public state4 = 4
    _toString() {
        console.log("访问到Control类中的私有属性state2:", this.state2)
    }
}

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

// 一个接口继承了具有私有成员(或受保护成员)的类,那么该接口只能被这个类的子类实现
class SubControl extends Control implements SelecetableControl {
    constructor() {
        super()
        console.log(this.state4)
    }
    select() { }
}
// new SubControl()._toString() // 访问到Control类中的私有属性state2: 2

let obj1: SubControl = <SubControl>{
    state3: 3,
    state4: 666,
    select: () => { },
    _toString: () => { console.log(111) }
}
console.log(obj1)

推荐阅读