【问题标题】:Typescript mixin fails when trying to use base class method尝试使用基类方法时,Typescript mixin 失败
【发布时间】:2021-11-17 02:58:28
【问题描述】:

MCVE

我想创建一个 mixin,它可以使用混入它的类的方法。但是这不起作用。

////////////////////
// Simple class
class User {  
  sayHello(msg:string){
      console.log(msg)
  }
}
// Needed for all mixins
type Constructor<T = {}> = new (...args: any[]) => T;
////////////////////
// A mixin that adds a method that uses a base class method
function Activatable<TBase extends Constructor>(Base: TBase) {
  return class extends Base {    
    activate() {      
      (Base as unknown as User).sayHello("activated")
    }
  };
}
////////////////////
// Using the composed class
////////////////////
const ActivableUser = Activatable(User)
const activableUser = new ActivableUser()
activableUser.activate()

运行失败并显示[ERR]: Base.sayHello is not a function

有什么方法可以创建一个可以访问基类方法和属性的 mixin?

【问题讨论】:

    标签: typescript mixins


    【解决方案1】:

    activate 方法中的Base 是类构造函数。它不是一个实例。而activate 是实例上的方法。

    但是由于activate是一个实例方法,你可以直接使用this来代替。

    只需将Base 替换为this 即可。

    function Activatable<TBase extends Constructor>(Base: TBase) {
      return class extends Base {    
        activate() {      
          (this as unknown as User).sayHello("activated")
        }
      };
    }
    

    Playground


    此外,如果你告诉 mixin 它依赖于哪些实例方法,你可以通过 unknown 摆脱这种讨厌的强制转换。

    function Activatable<
      TBase extends Constructor<{ sayHello(msg: string): void }>
    >(Base: TBase) {
      return class extends Base {    
        activate() {      
          this.sayHello("activated")
        }
      };
    }
    

    Playground

    【讨论】:

    • 我想知道是否可以使用具有许多方法的接口而不是手动编写Constructor&lt;{ sayHello(msg: string): void },所以如果我有一个带有方法sayHello(和其他方法)的接口CanSayHello,我该怎么做在这个构造函数定义中工作? (假设User被定义为实现该接口的类)
    • 您可以在Constructor&lt;WhateverTypeHere&gt; 中输入任何类型的对象。您可以放置​​一个具有该方法的接口。或者你甚至可以put a class in there。或者,如果您想简短一些,可以创建一个类型别名,例如 type UserMaker = Constructer&lt;User&gt;
    【解决方案2】:

    Fot 完整性,基于@Alex Wayne 的回答和他在评论中的额外指导,这是我真正想要的解决方案,即使用它必须实现的接口来约束基类,并从mixin 函数中的基类。

    Playground

    ////////////////////
    // Interface that our base class has to implement
    interface CanSayHello {
      sayHello(msg:string):void
    }
    
    ////////////////////
    // Base class
    class User implements CanSayHello {  
      sayHello(msg:string){
          console.log(msg)
      }
    }
    
    ////////////////////
    // Needed for all mixins
    type Constructor<T = {}> = new (...args: any[]) => T;
    
    ////////////////////
    // A mixin that adds a method that uses a base class method
    function Activatable<TBase extends Constructor<CanSayHello>>(Base: TBase) {
      return class extends Base {    
        activate() {      
          this.sayHello("activated")
        }
      };
    }
    
    ////////////////////
    // Creating the composed class
    const ActivableUser = Activatable(User)
    const activableUser = new ActivableUser()
    
    ////////////////////
    // Using the composed class
    activableUser.activate()
    

    【讨论】:

      猜你喜欢
      • 2021-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多