如何在TypeScript泛型中动态指定类型?

3
我应该如何修改WithArea函数的areaCalculator参数的通用类型参数U,使其扩展当前MixinFactory实例的基类?
type Constructor<T> = new (...args: any[]) => T;

interface IArea {
    readonly area: number;
}

class MixinFactory<T extends Constructor<Shape>> {
    constructor(public Superclass: T) {}

    WithArea(areaCalculator: <U extends Shape & IArea>(ctx: U) => number) {
        return new MixinFactory<T & Constructor<IArea>>(class extends this.Superclass implements IArea {
            get area(): number {
                return areaCalculator(this);
            }
        })
    }
}

class Shape {}

class RectRaw extends Shape {
    constructor(
        public x: number,
        public y: number,
        public w: number,
        public h: number) {
            super();
        }
}

const Rect = new MixinFactory(RectRaw).WithArea(ctx => {
    return ctx.w * ctx.h;
}).Superclass;

const rect = new Rect(10, 10, 20, 20);

console.log(rect.area);

在线代码编辑器


1
我花了一些时间才理解你的代码,它相当复杂。 - captain-yossarian from Ukraine
1个回答

3
您好!这段文字的翻译如下:

您的areaCalculator函数不需要是泛型的;没有必要添加额外的类型参数U,而且该类型参数不会被方法get area(): number暴露出来。

areaCalculator函数只需要定义为接受构造函数类型T返回的任何对象即可,因此使用InstanceType助手程序,我们可以提取它并直接在类型注释中使用:

class MixinFactory<T extends Constructor<Shape>> {
    constructor(public Superclass: T) {}

    WithArea(areaCalculator: (ctx: InstanceType<T> & IArea) => number) {
        return new MixinFactory<T & Constructor<IArea>>(class extends this.Superclass implements IArea {
            get area(): number {
                return areaCalculator(this as InstanceType<T> & IArea);
            }
        })
    }
}

请注意,需要类型断言`this as InstanceType<T> & IArea`,因为Typescript不能确定如果一个类扩展了类型为`T`的`this.Superclass`,那么它的实例必须具有类型`InstanceType<T>`。 点此查看示例

1
这是正确的。顺便说一下,有一个内置的实用程序类型InstanceType<T>,它与您的ConstructorReturnType<T>(我认为)相同。 - Linda Paiste
2
@LindaPaiste 感谢您指出这一点,我已经改进了答案。 - kaya3
在您的回答中,“ctx”也可以访问整个继承链,这是一个很好的奖励。谢谢! - Murolem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接