如何防止TypeScript中意外的类型兼容性

如何防止TypeScript中意外的类型兼容性,typescript,Typescript,假设我们有一个界面Animal interface Animal { amountOfLegs: number; } 然后两个不同的类实现了这个接口,Dog和Snake: class Dog implements Animal { constructor(public amountOfLegs: number) { } } class Snake implements Animal { amountOfLegs: number; constructor() {

假设我们有一个界面
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?


所以我的问题是:我能阻止这种行为吗?我知道这叫什么,但我看不出有什么办法可以阻止它。在我的tsconfig.json中使用
“strictFunctionTypes”:true
选项似乎没有任何作用。

我相信TypeScript会检查属性类型,所以您的问题是
Dog
Snake
具有相同的属性和类型。。。所以它们是相同的

界面动物{ Amontoflegs:数字; } 狗类动物{ 构造函数(公共数量:个){ } } 蛇类动物{ 公共数量:数量; 公害:布尔; 构造函数(){ 该值为0.Amontoflegs=0; 这是真的; } } 函数functionSpecificForSnake(snake:snake):无效{ //用蛇形物体做点什么。。。 } 福斯纳克(新狗(4));
目前来看,不,你不能。在您引用的链接中:“要检查y是否可以分配给x,编译器将检查x的每个属性,以在y中找到相应的兼容属性”。因此编译器忽略类的“实现接口”位,只查看每个类的形状

蛇和狗是同一个形状,因此可以相互分配

您可以尝试为每个类添加一个鉴别器,例如:

interface Animal {
    disc: string
    amountOfLegs: number;
}

class Dog implements Animal {
    disc = 'Dog' as const
    constructor(public amountOfLegs: number) {
    }
}

class Snake implements Animal {
    disc = 'Snake' as const
    amountOfLegs: number;

    constructor() {
        this.amountOfLegs = 0;
    }
}

function functionSpecificForSnake(snake: Snake): any {
    //Do something with the snake object...
}

functionSpecificForSnake(new Dog(4))
现在给出了错误

“Dog”类型的参数不能分配给“Snake”类型的参数。 属性“disc”的类型不兼容。
类型“Dog”不可分配给类型“Snake”(2345)

您的类
Dog
Snake
是等效的类型,因此就类型脚本而言,它们可以相互分配。您想要的行为是类型脚本没有的行为,但是您可以通过将类型更改为结构上不同的类型来模拟它

为此,您可以添加一个名为
\uu brand
的属性,它不会与类型可能具有的任何不动产冲突,并且该属性可以为每个类具有不同的类型;它可以是类本身,也可以是作为字符串文本的类名称。为了避免运行时的任何开销,您可以在不初始化属性的情况下声明该属性,因此该属性实际上并不存在,但Typescript认为它确实存在。要禁用未初始化属性的错误,可以将该属性设置为可选(或使用)

类狗实现动物{
私人只读品牌:狗;
构造函数(公共amountflegs:number){}
}
蛇类动物{
私人只读品牌:Snake;
Amontoflegs:数字;
构造函数(){
该值为0.Amontoflegs=0;
}
}
然后,如果您尝试在需要使用蛇的地方使用狗,您将得到一个类型错误,因为品牌属性的类型错误


我建议在您的问题中添加一个指向打字脚本的链接@sunknudsen完成