6、TS 类型兼容性

168 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

TS 如何判定两个类型是否兼容, 当两个类型兼容之后才能互相赋值。

鸭子辩型法 (子结构辩型法)

鸭式辨型来自于James Whitecomb Riley的名言:"像鸭子一样走路并且嘎嘎叫的就叫鸭子。"通过制定规则来判定对象是否实现这个接口。

抽象概念

假如 会嘎嘎叫、会游泳就是鸭子

我是一个人我会打篮球、rap、嘎嘎叫、游泳, 我拥有上面鸭子的全部属性 嘎嘎叫、游泳, 就可以认为我是一直鸭子。

基本类型:完全匹配

基本类型的数据, 只能类型一致, 才能认为是兼容的, 本文不做讨论(没有讨论的意义)。

对象类型: 鸭子辩型法

举个栗子

interface Duck {
    sound: '嘎嘎'
    swim(): void
}

定义一个接口 Duck 有两个属性 sound、swim

当有一个对象具有这个两个属性,他就是一个 Duck

interface Duck {
    sound: '嘎嘎'
    swim(): void
}

let person = {
    name: '伪装成鸭子的人',
    age: 18,
    sound: '嘎嘎',
    swim() {
        console.log('我会游泳')
    }
}

也许到现在你会认为 person 是一个 Duck

其实不是, 疑问:person 不是有 sound、swim么, 对也不全对!!!

因为Duck.sound是一个字面量类型嘎嘎, 而person.sound TS推断出来是一个 string 类型。

解决方法:类型断言

语法:数据 as 数据类型

person.sound 我清楚的知道是一个 嘎嘎 的字面量类型, 而不是 string 类型,但是 TS 不知道所以我可以强制让 TS 知道

interface Duck {
    sound: '嘎嘎'
    swim(): void
}

let person = {
    name: '伪装成鸭子的人',
    age: 18,
    sound: '嘎嘎' as '嘎嘎', //使用 as 关键字进行 断言
    swim() {
        console.log('我会游泳')
    }
}

使用方法:鸭子辩型法只适用于 间接赋值

const test: Duck = person //这样不报错 因为是间接赋值

const test1: Duck = {
    name: '伪装成鸭子的人',
    age: 18,
    sound: '嘎嘎' as '嘎嘎', //使用 as 关键字进行 断言
    swim() {
        console.log('我会游泳')
    }
} //使用对象字面量赋值, 会进行严格的类型检查

使用场景

通常使用在服务器返回的数据, 服务器返回了 n 多数据, 不可能对每一条数据进行约束, 所以用于约束一小部分使用到的数据就行了。

函数类型

很多时候都感觉不到 函数类型的存在, 因为函数约束太自然了

这里写一个 filter 函数

interface Condition {
    (item: number, index: number): boolean
}

function filter(data: number[], callbacl: Condition) {
    const result: number[] = []
    for (let i = 0; i < data.length; i++) {
        if (callbacl(data[i], i)) {
            result.push(data[i])
        }
    }
    return result
}

Condition 约束了函数的参数类型, 返回值类型。

下面在使用 filter 是两种方法都是合理的

filter([1, 2, 3, 4, 5], (item) => item > 2)

回调函数可以接受 个参数

filter([1, 2, 3, 4, 5], (item,i) => i % 2 !== 0)

回调函数可以接受 个参数

在使用阶段无比自然, 没有对参数的数量进行强校验, 参数不能多但可以少, 但函数的返回值是强约束。

总结

类型兼容性 一般发生在赋值, 对也赋值数据类型没有做特别强的校验, 保留了之前的好的开发习惯。