【前端,TypeScript】TypeScript速成(十):接口

发布于:2025-02-10 ⋅ 阅读:(30) ⋅ 点赞:(0)

接口

基本概念

在 TypeScript 当中,接口用于简单地描述类型,一个 employee 接口的定义如下:

interface Employee {
    name: string	// 行间加分号、逗号、不加都可以
    salary: number
}

使用 interface:

const emp1: Employee = {
    name: 'John',
    salary: 8000,
}

可以看到,interface 为类型的实例化提供了约束,Employee 类型只能包含 name 和 salary 两个变量。

一个更灵活的接口定义方法如下,在这个接口当中,我们进一步引入 bonus,但是 bonus 未必一定有:

interface Employee {
    name: string;
    salary: number
    bonus?: number	// 使用 ? 来表明 bonus 成员不一定在 Employee 接口当中有定义
}

function updateBonus(e: Employee, p: number) {
    if(!e.bonus) {
        e.bonus = e.salary * p
    }
}

我们通常不在接口当中定义方法。

可以在 interface 当中设置只读字段,在字段名之前加入 readonly 关键字即可,但是这个行为不是很常用。

接口的高级技巧

可选参数的串联 && 非空断言

假定现在我们定义的 Employee 接口当中,name 由两个字段组成,且包含可选字段,如果我们为接口定义了一个函数,用于判断接口当中的 name 字段是否合法,由于 name 当中包含可选字段,我们需要使用多个 if - else 来判断字段是否存在,产生大量的冗余代码。此时我们可以使用“可选参数的串联”这个技巧来规避上述冗余。一个糟糕的版本如下:

interface Employee {
    name?: {
        first: string
        last: string
    }
    salary: number
    bonus?: number
}

function hasBadName(e: Employee) {
    if(e.name)  return e.name.first.startsWith('AAA')
    else        return true
}

使用可选参数串联进行改进的版本如下:

interface Employee {
    name?: {
        first?: string
        last: string
    }
    salary: number
    bonus?: number
}

function hasBadName(e: Employee) {
    return e.name?.first?.startsWith("AAA")
}

可选字段串联同样是 typescript 的语法糖。可以使用!替代?,此时将告诉编译器,如果出错,后果自负,必须要在编译阶段报错。使用!表示字段一定不空,不需要编译器报错,这条性质叫做非空断言

接口的扩展

假定现在我们已经有了接口 HasName:

interface HasName {
    name?: {
        first?: string
        last: string
    }
}

我们想在 Employee 当中直接使用 HasName 当中的字段作为 Employee 的字段,可以使用 extends 关键字完成接口的扩展:

interface Employee extends HasName{
    salary: number
    bonus?: number
}

interface HasName {
    name?: {
        first?: string
        last: string
    }
}

类型的并 && 类型断言

假定现在我们有两个不同的接口,并且有一个函数,需要使用这个函数来判断传入的参数是哪个接口,根据传入的接口来执行特定的任务。如果两个接口具有相同的字段,那么对于函数来说,只能使用字段的并集,这条性质叫做接口的并:

interface WxButton {
    visible: boolean
    enabled: boolean
    onClick(): void
}

interface WxImage {
    visible: boolean
    src: string
    width: number
    height: number
}

// Union of types
function hideElement(e: WxButton | WxImage) {
    // 只能使用共有的属性, 比如 e.visible
    // ... ... ...
}

如果想要根据传入的实参判断接口的类型,我们不能够使用 typeof 关键字,而应该使用接口的断言:

function processElement(e: WxButton | WxImage) {
    // 判断传入的 e 的类型
    if((e as any).onClick) {
        // 使用 as any 告诉 TS 编译器不要帮助我们判断
        // e as WxButton 叫做类型断言
        const btn = e as WxButton
        btn.onClick()
    } else {
        const img = e as WxImage
        // e as WxImage 是类型断言
        console.log(img.src)
    }
}

一个更优雅的写法如下,在这个写法中,新定义了一个辅助函数,它的返回值是e is WxButton

function elegentProcessElement(e: WxButton | WxImage) {
    if(isButton(e)) {
        e.onClick()
    } else {
        console.log(e.src)
    }
}

function isButton(e: WxButton | WxImage): e is WxButton {
    return (e as WxButton).onClick !== undefined
}

网站公告

今日签到

点亮在社区的每一天
去签到