类型兼容性
假定有两个类型 A、B,如果能够将 B 赋值给 A,那么 B 和 A 类型兼容。
那么如何判读两个类型是否兼容呢?这里就需要引入鸭子辩型法的概念。
鸭子辩型法(子结构辩型法)
鸭子辩型法并不是判断一个东西是否真的鸭子,而是判断一个东西是否具有鸭子的特征。
即:目标类型需要具有某一些特征,赋值类型只需要满足这些特征即可。
鸭子辩型法主要应用在对象类型和函数类型,而对于基本类型,则是采用完全匹配的方式,因为基本类型差异巨大。
对象类型
tsx
interface Duck {
sound: '嘎嘎嘎'
swim(): void
}
let person = {
name: '伪装成鸭子的人',
age: 18,
// 类型断言,将字符串'嘎嘎嘎'断言为字面量类型'嘎嘎嘎'
sound: '嘎嘎嘎' as '嘎嘎嘎',
swim() { console.log(`${this.name}正在游泳,并发出了${this.sound}的声音`) }
}
let duck: Duck = person // 可以正常赋值但有意思的是,如果直接使用对象字面量进行赋值,是会报错的。
tsx
interface Duck {
sound: '嘎嘎嘎'
swim(): void
}
// 无法正常赋值
let duck: Duck = {
name: '伪装成鸭子的人',
age: 18,
// 类型断言,将字符串'嘎嘎嘎'断言为字面量类型'嘎嘎嘎'
sound: '嘎嘎嘎' as '嘎嘎嘎',
swim() { console.log(`${this.name}正在游泳,并发出了${this.sound}的声音`) }
}typescript 有这样的规则,使用字面量直接赋值的时候,会采用严格的规则判断,这个字面量是只有这个变量使用的,既然如此就应该必须按照这个变量的类型去定义。而如果是使用其他变量来赋值的话,由于无法控制其他变量,因此会采用较为宽松的规则。
函数类型
函数类型的兼容判断,主要出现在回调函数中。
tsx
interface Condition {
(n: number, i): void
}
function sum(list: number[], callback: Condition) {
let s = 0;
list.forEach((n, i) => {
if (callback(n, i)) {
s += n;
}
});
return s;
}
// callback形参传递了两个参数,但实参中只取了一个参数,但这并不会报错
sum([1, 2, 3, 4, 5], n => n%2);函数类型兼容有这样的规则:
- 实参可以少,但不可以多
- 函数要求有返回值,就必须有返回值