Typescript:类扩展了泛型类型

Typescript:类扩展了泛型类型,typescript,Typescript,我知道它太泛型了,但我希望创建一个类,该类包含所有来自泛型类型的道具和原型,如下所示: class GenericExtend<T> extends T { constructor(data: T) { // here is a workaround to make these 2 classes unique const proto = { ...GenericExtend.prototype }; Object.assign

我知道它太泛型了,但我希望创建一个类,该类包含所有来自泛型类型的道具和原型,如下所示:

class GenericExtend<T> extends T {
    constructor(data: T) {
        // here is a workaround to make these 2 classes unique
        const proto = { ...GenericExtend.prototype };
        Object.assign(proto, Object.getPrototypeOf(data));
        Object.setPrototypeOf(this, proto);
        Object.assign(this, data);
    }

    GenericMethod() { }
}
const obj = new GenericExtend<Model>(data);
obj.GenericMethod(); // ok
obj.ModelMethod(); // good!
const obj: GenericExtend & Model = new GenericExtend(data) as any;
我的解决方案之一是使用交叉点,类似这样:

class GenericExtend<T> extends T {
    constructor(data: T) {
        // here is a workaround to make these 2 classes unique
        const proto = { ...GenericExtend.prototype };
        Object.assign(proto, Object.getPrototypeOf(data));
        Object.setPrototypeOf(this, proto);
        Object.assign(this, data);
    }

    GenericMethod() { }
}
const obj = new GenericExtend<Model>(data);
obj.GenericMethod(); // ok
obj.ModelMethod(); // good!
const obj: GenericExtend & Model = new GenericExtend(data) as any;

它奏效了,但我不太喜欢。有更好的方法吗?

TypeScript不会让您实现或扩展另一种类型
T
,除非
T
的所有键在编译时都是静态已知的。这可以防止
类GenericExtend实现T{…}
成为您可以编写的东西

相反,您必须使用交叉点来获得此行为。。。但是,如果需要,可以将类型断言限制在构造函数中,以便后续使用不需要它。让我们把
GenericExtend
改名为:

class _GenericExtend<T> {
  constructor(data: T) {
    const proto = { ..._GenericExtend.prototype };
    Object.assign(proto, Object.getPrototypeOf(data));
    Object.setPrototypeOf(this, proto);
    Object.assign(this, data);
  }
  GenericMethod() { }
}
最后的
和任何
一样是我们需要的类型断言。现在,您应该能够获得所需的行为:

type GenericExtend<T> = _GenericExtend<T> & T;
const GenericExtend: new <T>(data: T) => GenericExtend<T> = _GenericExtend as any;
interface Model {
  ModelMethod(): void;
}
declare const data: Model;

const obj = new GenericExtend(data);
obj.GenericMethod(); // ok
obj.ModelMethod(); // ok

我遇到了类似的需求,并最终通过以下方式实现了它,通过这种方式,不需要严格的交叉点(您可以为类型检查定义专用类型),希望它能有所帮助

class A {
  a() {
    ...
  }
}

class B {
  b() {
    ...
  }
}

type Constructor = new (...args: any[]) => any

function genericExtend<T extends Constructor>(target: T) {
  return class GenericExtended extends target {
    constructor(...args: any[]) {
      super(...args)
    }

    genericMethod() {
      ...
    }
  }
}

const instanceOfA: GenericExtended & A = new (genericExtend(A))()
const instanceOfB = new (genericExtend(B))()

instanceOfA.a() // ok with type checking
instanceOfA.genericMethod() // ok with type checking

instanceOfB.b() // ok without type checking
instanceOfB.genericMethod() // ok without type checking
A类{
(){
...
}
}
B类{
b(){
...
}
}
类型构造函数=新建(…参数:any[])=>any
函数genericExtend(目标:T){
返回类GenericExtended扩展目标{
构造函数(…参数:任意[]){
超级(…args)
}
genericMethod(){
...
}
}
}
const instanceOfA:GenericExtended&A=new(genericExtend(A))()
const instanceOfB=new(genericExtend(B))()
instanceOfA.a()//类型检查正常
instanceOfA.genericMethod()//通过类型检查确定
instanceOfB.b()//不进行类型检查即可
instanceOfB.genericMethod()//不进行类型检查即可

太棒了!如果模型是一个类而不是一个接口,它会工作吗?它应该在语法上工作,结果对象应该在结构上与类类型匹配,但它可能不适用于
instanceof
或类原型属性。这些东西需要在
GenericExtend
构造函数的实现中解决。。。我不相信自己会写那封信。听起来,如果您的用例是扩展一个类,那么您可能正在寻找它。您是对的!我想mixins会解决我的问题。谢谢@jcalz的这个解决方案。我进一步简化了它,以避免额外的类型和强制转换:const GenericExtend=\u GenericExtend as new(data:T)=>\u GenericExtend&T