首页 > 解决方案 > Typescript 中通用 Mixins 的解决方法

问题描述

我对 Typescript 比较陌生。似乎带有泛型的混合是一个问题,我很快就遇到了它。考虑以下示例:

编辑:将提香的答案整合到方法 2 中并添加setValue()以更好地说明新问题。)

class A<T> {
  public constructor(public a: T) {}
  public setValue(a: T): void {this.a = a;}
}
class B<T> extends A<T> {public constructor(public a: T, public b: T) {super(a);}}

// approach 1
function mixinC(Base: ???) { // ??? = typeof A vs. ??? = typeof B vs. ??? = any
  return class CMixin<T> extends Base<T> {}; //...
}
// approach 2
type Constructor<T> = new (...args: any[]) => T;
function mixinC<T extends Constructor<A<unknown>>>(Base: T) {
  return class CMixin extends Base {}; //...
}

// test 1
class C<T> extends mixinC(A)<T> {}
interface C<T> extends A<T> {}
const c = new C<string>('123');
c.setValue(7); // no error, although 7 is not string
console.log(c.a);

// test 2
class D<T> extends mixinC(B)<T> {}
interface D<T> extends B<T> {}
const d = new D<string>('465', '789');
console.log(d.a, d.b);

我希望这两种测试都有效,但两种方法都不起作用。

如果有一种方法可以动态地告诉编译器Base将会是typeof Aor typeof B,那么第一种方法会起作用(我认为),但mixinC<T>(Base: typeof T)由于 T 是一种类型而不是值,所以它不起作用。我也尝试过any作为类型;这似乎在表面上工作,但我可以访问C(例如c.xyz)的每个实例上的任意、未定义的属性。

第二种方法原则上与ES6 Mixin 在 TypeScript 中具有泛型类型非常相似,但主要区别在于A(与BaseClass那里相比)这里是泛型类型。那我应该换什么???和?如果我可以??? = A<T2>使用参数类型T2,也许它会起作用,但我应该在哪里定义这个参数?

@编辑c.setValue(7);可能不会引发错误,因为现在实际上共存了两个版本setValuestring一个(正确的)和unknown一个,后者允许7.

标签: typescriptgenericsmixins

解决方案


我不确定为什么Constructor<any>允许您访问任何属性,我实际上会将其归类为 Typescript 错误。使用{}instead 似乎可以防止这种不良行为,并且还可以将泛型参数从目标类转发到生成的混合类:

class A<T> {public constructor(public a: T) {}}
class B<T> extends A<T> {public constructor(public a: T, public b: T) {super(a);}}

type Constructor<T> = new (...args: any[]) => T;
function mixinC<T extends Constructor<A<unknown>>>(Base: T) {
  return class CMixin extends Base {
      test() {
          this.a
      }
  }; //...
}

// test 1
class C<T> extends mixinC(A)<T> {}
const c = new C<string>('123');
console.log(c.a);
c.xyzqqq // error


// test 2
class D<T> extends mixinC(B)<T> {}
const d = new D<string>('465', '789');
console.log(d.a, d.b);

游乐场链接


推荐阅读