我有一个名为Mixin
的函数,该函数接受单个参数。该参数应为“类工厂混合”。
例如,假设我具有此类工厂mixin函数:
type Constructor<T = any, A extends any[] = any[]> = new (...a: A) => T
const CoolMixin = <T extends Constructor>(Base: T) => {
return class CoolMixin extends Base {
coolProp = 42
}
}
const CoolFoo = CoolMixin(class Foo {
foo = 'asdf'
})
const c = new CoolFoo()
// it works:
c.foo
c.coolProp
如您所见,它接受一个基类并返回一个新类,并且工作正常。
我有一个Mixin
实用程序,它具有一个mixin函数,并为其提供了很酷的功能,例如hasInstance
支持,针对基类重复应用程序进行缓存以及其他功能。
在普通的JavaScript中,我可以这样使用它:
// Mixin returns an application of the Mixin function (a class) with
// a default base class applied (Object by default):
const CoolMixin = Mixin((Base) => {
return class CoolMixin extends Base {
coolProp = 42
}
})
// Here, CoolMixin is `class CoolMixin extends Object {...}`,
// so we can use it like a regular class:
let CoolFoo = class Foo extends CoolMixin {
foo = 'asdf'
}
// Mixin returns that class with a static `.mixin` property containing
// the original mixin function, so we can also use it as a mixin:
CoolFoo = CoolMixin.mixin(class Foo {
foo = 'asdf'
})
// either of the two versions will work the same:
const c = new CoolFoo()
c.foo
c.coolProp
因此,我的实用程序的便利性(除了诸如缓存,hasInstance等功能之外)是可以使用的,但它是最方便的。这是另外两个示例:
// suppose One and Two are mixins created with my Mixin utility.
// Use regular extension:
class Foo extends One {...}
class Bar extends Two {...}
// or compose them together:
class Baz extends One.mixin(Two) {...}
因此,我想弄清楚如何在TypeScript中为此Mixin
实用程序进行键入。
我的第一个尝试是以下操作,它不起作用,但我认为它表明了我要执行的操作的想法:
type Constructor<T = any, A extends any[] = any[]> = new (...a: A) => T
type MixinFunction = <TSub, TSuper>(base: Constructor<TSuper>) =>
Constructor<TSub & TSuper>
declare function Mixin<TSub, TSuper, T extends MixinFunction>(mixinFn: T):
Constructor<TSub & TSuper> & {mixin: T}
// Then using it like so:
const CoolMixinFunction = <T extends Constructor>(Base: T) => {
return class CoolMixin extends Base {
coolProp = 42
}
}
const CoolMixin = Mixin(CoolMixinFunction)
const CoolFoo = CoolMixin.mixin(class Foo {
foo = 'asdf'
}
const c = new CoolFoo()
c.foo
c.coolProp
const CoolBar = class Bar extends CoolMixin {
bar = 'asdf'
})
const b = new CoolBar()
b.bar
b.coolProp
您可能会推断,我正在尝试键入Mixin
工具,以便它接受mixin函数,并且Mixin
调用的返回类型应该是从mixin函数,并且返回的类还应该具有.mixin
属性,该属性与传入的mixin函数的类型相同。
我知道我做错了。我不清楚如何在此处使用类型推断。
似乎新的"Higher order function type inference"功能在这里可能有用。
如何输入Mixin
实用程序?没有该更高阶功能,我可以这样做吗?以及如何使用该功能?
答案 0 :(得分:1)
这使得代码可以编译,并且所有prop类型都可以按预期工作,我只是不确定class Bar extends CoolMixin
的语义是什么。我看到它直接扩展混入的方式就像您只是将mixin类用作基类而没有将其应用于任何东西一样
type Constructor<T = any, A extends any[] = any[]> = new (...a: A) => T
// The function is not generic on two type parameters:
// it is a generic type on TSub as that is fixed during definition
// and a generic function on TSuper as that is defined during the mix-in call
// although TSub does not much matter so we can erase it
type MixinFunction = <TSuper>(base: Constructor<TSuper>) => Constructor<TSuper>
declare function Mixin<T extends MixinFunction>(mixinFn: T): ReturnType<T> & { mixin: T }
// Then using it like so:
// The {} in the extends is critical to allow ReturnType above to get an insatnce of mixin as if applied to {}.
const CoolMixinFunction = <T extends Constructor<{}>>(Base: T) => {
return class CoolMixin extends Base {
coolProp = 42
}
}
const CoolMixin = Mixin(CoolMixinFunction)
const CoolFoo = CoolMixin.mixin(class Foo {
foo = 'asdf'
})
const c = new CoolFoo()
c.foo
c.coolProp
const CoolBar = class Bar extends CoolMixin {
bar = 'asdf'
}
const b = new CoolBar()
b.bar
b.coolProp