【问题标题】:How to dynamically specify type in TypeScript generics?如何在 TypeScript 泛型中动态指定类型?
【发布时间】:2021-06-18 08:00:28
【问题描述】:

我应该如何修改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);

Playground

【问题讨论】:

  • 我花了一段时间才理解你的代码,相当复杂)

标签: typescript mixins typescript-generics


【解决方案1】:

您的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&lt;T&gt; &amp; IArea,因为 Typescript 无法确定如果一个类扩展了 T 类型的 this.Superclass,那么它的实例必须具有 InstanceType&lt;T&gt; 类型。

Playground Link

【讨论】:

  • 这是正确的。仅供参考,有一个内置实用程序类型 InstanceType (我认为)与您的 ConstructorReturnType 相同。
  • @LindaPaiste 感谢您指出这一点,我已经改进了答案。
  • 在您的回答中,ctx 还可以访问整个继承链,这是一个不错的奖励。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-03
  • 2020-03-19
  • 2020-11-11
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
  • 2019-05-30
相关资源
最近更新 更多