尝试使用基本 class 方法时 Typescript mixin 失败
Typescript mixin fails when trying to use base class method
我想创建一个 mixin,它可以使用它所混入的 class 的方法。然而,这是行不通的。
////////////////////
// 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
。
有什么方法可以创建一个可以访问基础 class 方法和属性的混入?
activate
方法中的Base
是class构造函数。它不是一个实例。 activate
是实例上的方法。
但由于 activate
是一个实例方法,您可以只使用 this
代替。
只需将 Base
替换为 this
就可以了。
function Activatable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
activate() {
(this as unknown as User).sayHello("activated")
}
};
}
此外,如果您告诉 mixin 它依赖于哪些实例方法,您可以通过 unknown
摆脱那个令人讨厌的转换。
function Activatable<
TBase extends Constructor<{ sayHello(msg: string): void }>
>(Base: TBase) {
return class extends Base {
activate() {
this.sayHello("activated")
}
};
}
Fot 完整性,基于@Alex Wayne 的回答和他在评论中的附加指导,这是我真正想要的解决方案,即用它必须实现的接口来约束基础 class并在 mixin 函数中从基础 class 中要求此接口。
////////////////////
// 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()
我想创建一个 mixin,它可以使用它所混入的 class 的方法。然而,这是行不通的。
////////////////////
// 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
。
有什么方法可以创建一个可以访问基础 class 方法和属性的混入?
activate
方法中的Base
是class构造函数。它不是一个实例。 activate
是实例上的方法。
但由于 activate
是一个实例方法,您可以只使用 this
代替。
只需将 Base
替换为 this
就可以了。
function Activatable<TBase extends Constructor>(Base: TBase) {
return class extends Base {
activate() {
(this as unknown as User).sayHello("activated")
}
};
}
此外,如果您告诉 mixin 它依赖于哪些实例方法,您可以通过 unknown
摆脱那个令人讨厌的转换。
function Activatable<
TBase extends Constructor<{ sayHello(msg: string): void }>
>(Base: TBase) {
return class extends Base {
activate() {
this.sayHello("activated")
}
};
}
Fot 完整性,基于@Alex Wayne 的回答和他在评论中的附加指导,这是我真正想要的解决方案,即用它必须实现的接口来约束基础 class并在 mixin 函数中从基础 class 中要求此接口。
////////////////////
// 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()