一起养成写作习惯!这是我参与「掘金日新计划 · 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)
回调函数可以接受 二 个参数
在使用阶段无比自然, 没有对参数的数量进行强校验, 参数不能多但可以少, 但函数的返回值是强约束。
总结
类型兼容性 一般发生在赋值, 对也赋值数据类型没有做特别强的校验, 保留了之前的好的开发习惯。