假设我们有一个接口Animal
interface Animal {
amountOfLegs: number;
}
然后两个不同的类Dog
和Snake
实现这个接口:
class Dog implements Animal {
constructor(public amountOfLegs: number) {
}
}
class Snake implements Animal {
amountOfLegs: number;
constructor() {
this.amountOfLegs = 0;
}
}
然后我们要创建一个特定于Snake的函数:
function functionSpecificForSnake(snake: Snake): any {
//Do something with the snake object...
}
但是当函数被一个Dog对象调用时,TS并不抱怨错误的类型:
functionSpecificForSnake(new Dog(4)); // No compiler error, but possible runtime error?
Playground链接
所以我的问题是:我知道这叫做type compatibility,但是我没有找到一种方法来阻止它。在我的tsconfig.json中使用"strictFunctionTypes": true
选项似乎没有任何作用。
3条答案
按热度按时间ws51t4hk1#
你的类
Dog
和Snake
是structurally等价类型,所以就Typescript而言,它们是可以相互赋值的。你想要的行为是nominal type system的行为,Typescript没有,但是你可以通过改变类型使之在结构上不同来模拟它。为此,您可以添加一个名为
__brand
之类的属性,它不会与类型可能具有的任何真实的属性冲突,并且该属性对于每个类可以具有不同的类型;它可以简单地是类本身,或者是类的名称作为字符串文字。为了避免在运行时的任何开销,你可以声明属性而不初始化它,这样属性就不真正存在,但是Typescript认为它存在。要禁用未初始化属性的错误,你可以使属性可选,或者使用!
而不是?
来向编译器隐瞒正在初始化的属性。然后,如果您尝试在预期
Snake
的地方使用Dog
,则会得到类型错误,因为__brand
属性的类型错误。Playground链接
3okqufwl2#
我相信TypeScript会检查属性类型,所以您的问题是
Dog
和Snake
具有相同的属性和类型...所以它们是相同的。请参见TypeScriptPlayground。
hyrbngr73#
就目前情况而言,不,你不能。在你引用的链接中:“为了检查y是否可以赋给x,编译器检查x的每个属性以在y中找到对应的兼容属性”。因此编译器忽略类的“implements interfaces”位,而只查看每个类的形状。
蛇和狗是相同的形状,因此可以指定给对方。
您可以尝试为每个类添加一个鉴别器,类似于:
这将给出错误
“Dog”类型的参数不能赋给“Snake”类型的参数。属性“disc”的类型不兼容。类型““Dog”"不能赋给类型““Snake”“。(2345)