typescript中的抽象泛型类

typescript中的抽象泛型类,typescript,Typescript,我在typescript中有一个抽象泛型类,它有一个泛型方法,参数为class type variable。我尝试在派生类中实现抽象方法,发现typescript编译器并没有检查派生方法中的参数类型 这里有一个例子。我预计它在编译时会在process方法Class1上失败,因为参数的类型是错误的 我做错什么了吗?还是设计的?或者typescript编译器中的错误 class Product { id: number; name: string; } class Customer {

我在typescript中有一个抽象泛型类,它有一个泛型方法,参数为class type variable。我尝试在派生类中实现抽象方法,发现typescript编译器并没有检查派生方法中的参数类型

这里有一个例子。我预计它在编译时会在process方法Class1上失败,因为参数的类型是错误的

我做错什么了吗?还是设计的?或者typescript编译器中的错误

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);
  }
}
类产品{
id:编号;
名称:字符串;
}
类客户{
id:编号;
名称:字符串;
地址:字符串;
}
导出抽象类基类{
受保护的抽象过程(参数:TParam):无效;
}
导出类Class1扩展了基类{
受保护的过程(参数:产品):无效{
控制台日志(param);
}
}

该行为不是错误

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

请注意,
客户
可分配给
产品
,因为每个
客户
都有一个
编号
值的
id
属性和一个
字符串
值的
名称
属性。反之则不然<代码>产品不可分配给
客户
,因为并非每个
产品
都有必要的
地址
属性

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

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);
  }
}
在这种情况下,
BaseClass
应该有一个接受
Customer
process()
方法。但是这个
process()
接受更广泛的类型
Product
。可以吗?对因为如果
process()
接受任何
Product
参数,那么它肯定会接受任何
Customer
参数(因为
Customer
是一种特殊的
Product
,因此
Class1
正确地扩展了
BaseClass
)。这是一个方法参数的演示;子类方法可以接受比超类型上的同一方法更宽的参数。TypeScript确实允许方法参数是逆变的,因此没有错误

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

export class Class2 extends BaseClass<Product> {
  protected process(param: Customer): void { // no error, bivariant
    console.log(param);
  }
}
导出类Class2扩展了基类{
受保护进程(参数:Customer):void{//无错误,双变量
控制台日志(param);
}
}

概括地说:您可以将属性添加到
Customer
Product
中,以使它们在结构上不相关,或者您可以将它们单独放置,然后
Class1.process()
将无误编译。无论哪种方式,编译器都按预期运行


希望有帮助。祝你好运

谢谢你这么详细的解释。我期望像C中那样的行为#
export class Class2 extends BaseClass<Product> {
  protected process(param: Customer): void { // no error, bivariant
    console.log(param);
  }
}