![](/img/trans.png)
[英]How to explicitly annotate the return type of a TypeScript mixin factory function?
[英]Result of TypeScript class factory mixin "is not a constructor function"
问题是 mixin 将返回 mixin 添加的内容与原始构造函数T
的类型之间的交集。 这在非通用上下文中效果很好,并且生成的合并类将起作用。 问题在于,在另一个 mixin 中, T
尚不可知,因此交集mxinStuff & T
将无法解析为构造函数:
function mixin1<T extends new (... a: any[]) => any> (ctor: T) {
return class WithMixin1 extends ctor {
mixin1() {}
}
}
function mixinMixed<T extends new (... a: any[]) => any> (ctor: T) {
return class WithMixin2 extends mixin1(ctor) { // Type '{ new (...a: any[]): mixin1<T>.WithMixin1; prototype: mixin1<any>.WithMixin1; } & T' is not a constructor function type.
mixin2() {}
}
}
我们可以对mixin1
的结果进行一些类型手术,以获得作为新类的基类型工作,然后断言新类是将产生的,就好像我们扩展了我们最初想要进行扩展的方式一样:
function mixin1<T extends new (... a: any[]) => any> (ctor: T) {
return class WithMixin1 extends ctor {
mixin1() {}
static staticMixin1() {}
}
}
const mixin1BaseType = () => mixin1(class{});
type Mixin1Type = ReturnType<typeof mixin1BaseType>
function mixinMixed<T extends new (... a: any[]) => {a : string }> (ctor: T) {
class WithMixin2 extends (mixin1(ctor) as unknown as {
new (... a: any[]): {a : string } // we pretend this returns the constraint of T
} & Mixin1Type /* add mixin back in but as instantiated for an empty class*/ ) {
mixin2() {
this.a
this.mixin1()
WithMixin2.staticMixin1();
}
static staticMixin2() {}
}
return WithMixin2 as unknown as {
new (...a: ConstructorParameters<T>): WithMixin2 & InstanceType<T>
} & T & Mixin1Type & typeof WithMixin2
}
type AnyContructor = new (... a: any[]) => any
let m = mixinMixed(class {
a: string = "a";
b: string = "b";
m() {}
static staticM() {}
})
let s = new m();
// instance members are accessible
s.a
s.b
s.m();
s.mixin1();
s.mixin2();
// Staic methods are accessible
m.staticMixin1()
m.staticMixin2()
m.staticM();
console.log(s)
知道为什么上面的答案如此复杂。 你可以只做InstanceType<typeof YourMixedType>
。
基于TypeScript 文档的示例
class Sprite {
name = "";
x = 0;
y = 0;
constructor(name: string) {
this.name = name;
}
}
type Constructor = new (...args: any[]) => {};
// This mixin adds a scale property, with getters and setters
// for changing it with an encapsulated private property:
function Scale<TBase extends Constructor>(Base: TBase) {
return class Scaling extends Base {
// Mixins may not declare private/protected properties
// however, you can use ES2020 private fields
_scale = 1;
setScale(scale: number) {
this._scale = scale;
}
get scale(): number {
return this._scale;
}
};
}
type Scalable = InstanceType<ReturnType<typeof Scale>>;
const EightBitSprite = Scale(Sprite);
type EightBitSpriteType = InstanceType<typeof EightBitSprite>;
const flappySprite = new EightBitSprite("Bird");
// Now lets use the types!
foo(flappySprite);
bar(flappySprite);
baz(flappySprite);
function foo(sprite: EightBitSpriteType) {
}
function bar(sprite: Scalable) {
}
function baz(sprite: Sprite) {
}
在这里查看它的实际效果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.