typescript中的抽象泛型类



我在typescript中有一个抽象泛型类,它有一个带有类类型变量参数的泛型方法。我尝试在派生类中实现抽象方法,发现typescript编译器不检查派生方法中参数的类型。

下面是一个例子。我预计它在编译时会在Class1进程方法上失败,因为参数类型错误。

我做错什么了吗?或者是故意的?或打字脚本编译器中的错误

class Product {
id: number;
name: string;
}
class Customer {
id: number;
name: string;
address: string;
}
export abstract class BaseClass<TParam> {
protected abstract process(param: TParam): void;
}
export class Class1 extends BaseClass<Customer> {
protected process(param: Product): void {
console.log(param);
}
}

该行为不是bug。

TypeScript使用结构类型系统,因此,如果两个对象类型具有兼容的属性,即使这些类型具有不同的名称或来自不同的命名类/接口,它们也是兼容的。

注意,Customer可分配给Product,因为每个Customer都具有number值的id属性和string值的name属性。事实并非如此;Product不可分配给Customer,因为不是每个Product都具有必要的address属性。

这是个错误吗?编译器认为CustomerProduct的一种特殊类型,这对您的代码来说是个问题吗?如果是这样的话,最简单的方法就是为每个类型添加一个属性,编译器可以用来区分它们。例如:

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);
}
}

或者编译器认为CustomerProduct的一种特殊类型也没关系。在这种情况下,您可以不使用您的类型,我们可以检查为什么process()不会导致编译器错误:

export class Class1 extends BaseClass<Customer> {
protected process(param: Product): void { // no error
console.log(param);
}
}

在这种情况下,BaseClass<Customer>应该有一个接受Customerprocess()方法。但是该CCD_ 20接受更宽类型的CCD_。这样可以吗?对因为如果process()接受任何Product自变量,那么它肯定接受任何Customer自变量(因为CustomerProduct的特殊类型,所以Class1适当地扩展了BaseClass<Customer>(。这演示了方法参数是如何反变的;子类方法可以接受比超类型上的相同方法更宽的参数。TypeScript确实允许方法参数是相反的,因此没有错误。

方法参数协变是不安全的(其中子类方法接受比它们各自的超类方法更具体的参数类型(,但包括TypeScript在内的一些语言允许这表示一些常见用例。也就是说,尽管TypeScript缺乏类型安全性,但它允许方法参数同时是反变量和协变的,也称为双变量。因此,如果你用另一种方式做,也不会有错误:

export class Class2 extends BaseClass<Product> {
protected process(param: Customer): void { // no error, bivariant
console.log(param);
}
}

概括一下:您可以将属性添加到CustomerProduct,使它们在结构上不相关,也可以不使用它们,Class1.process()将编译而不会出错。无论哪种方式,编译器都按预期运行。

希望能有所帮助。祝你好运

最新更新