该行为不是错误。
TypeScript 使用structural 类型系统,因此如果两个对象类型具有兼容的属性,则它们是兼容的,即使类型具有不同的名称或来自不同的命名类/接口。
然后请注意,Customer 可以分配给 Product,因为每个 Customer 都有一个 number-valued id 属性和一个 string-valued name 属性。反过来是不正确的。 Product 不能分配给Customer,因为不是每个Product 都具有必要的address 属性。
这是一个错误吗?编译器认为Customer 是一种特殊的Product,对您的代码来说是个问题吗?如果是,最简单的解决方法是为每种类型添加一个属性,编译器可以使用它来区分它们。例如:
class Product {
id!: number;
name!: string;
type?: "product"
}
class Customer {
id!: number;
name!: string;
address!: string;
type?: "customer"
}
现在代码会根据需要给你一个错误:
export abstract class BaseClass<TParam> {
protected abstract process(param: TParam): void;
}
export class Class1 extends BaseClass<Customer> {
protected process(param: Product): void { // error!
// ~~~~~~~ <-- Type 'Customer' is not assignable to type 'Product'.
console.log(param);
}
}
或者编译器认为Customer 是Product 的一种特殊类型也可以。在这种情况下,您可以不理会您的类型,我们可以检查为什么 process() 不会导致编译器错误:
export class Class1 extends BaseClass<Customer> {
protected process(param: Product): void { // no error
console.log(param);
}
}
在这种情况下,BaseClass<Customer> 应该有一个接受Customer 的process() 方法。但是这个process() 接受更广泛的类型Product。可以吗?是的!因为如果process() 接受任何Product 参数,那么它肯定 接受任何Customer 参数(因为Customer 是Product 的一种特殊类型,因此Class1 正确扩展BaseClass<Customer>)。这是对方法参数如何contravariant 的演示;允许子类方法接受比超类型上的相同方法更宽 的参数。 TypeScript 确实允许方法参数是逆变的,因此没有错误。
将方法参数设为covariant不安全(其中子类方法接受比它们各自的超类方法更具体的参数类型),但有些语言包括 TypeScript 允许它代表一些常见的用例。也就是说,TypeScript 允许方法参数既是逆变的又是协变的,也称为bivariant,尽管它缺乏类型安全性。因此,如果您以另一种方式进行操作,也不会出现错误:
export class Class2 extends BaseClass<Product> {
protected process(param: Customer): void { // no error, bivariant
console.log(param);
}
}
回顾一下:您可以向Customer 和Product 添加属性以使它们在结构上不相关,或者您可以不理会它们,Class1.process() 将编译而不会出错。无论哪种方式,编译器都按预期运行。
希望对您有所帮助。祝你好运!