【问题标题】:Workaround for Generic Mixins in TypescriptTypescript 中通用 Mixins 的解决方法
【发布时间】:2020-08-25 14:27:01
【问题描述】:

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

编辑:将 Titian 的答案整合到方法 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 A 还是typeof B,第一种方法会起作用(我认为),但mixinC&lt;T&gt;(Base: typeof T) 不起作用,因为 T 是一个类型而不是一个值。我也试过any作为类型;这似乎在表面上起作用,但我可以访问C 的每个实例上的任意未定义属性(例如c.xyz)。

第二种方法原则上与ES6 Mixin with generic type in TypeScript 非常相似,但主要区别在于A(与那里的BaseClass 相当)是一个泛型类型。那我应该换什么???和?如果我可以使用参数类型T2 执行??? = A&lt;T2&gt;,也许它会起作用,但是我应该在哪里定义这个参数?

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

【问题讨论】:

    标签: typescript generics mixins


    【解决方案1】:

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

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

    Playground Link

    【讨论】:

    • 很有趣,谢谢。但这里的问题是BaseA(或B)无关。所以,如果CMixin 包含例如。一个方法test() {console.log(this.a);},这是行不通的,因为a 不存在。
    • @Remirror A&lt;unknown&gt;(或A&lt;any&gt;)应该可以代替{},如果你想访问A的特定成员(编辑答案)
    • 我也试过了,但除了玩具例子,这应该行不通。我已经相应地编辑了我的问题以说明问题(请参阅setValue 方法)。
    猜你喜欢
    • 1970-01-01
    • 2021-07-17
    • 2017-10-18
    • 2017-02-23
    • 1970-01-01
    • 2021-10-22
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多