如何在不重复签名的情况下为泛型类创建工厂函数

时间:2019-12-14 01:36:45

标签: typescript

示例代码:

interface ValueGenerator {
    next(): any;
}

class NumberGenerator {
    next(): number {
        return 1;
    }
}

class ArrayGenerator<T extends ValueGenerator> {

    private generator: T;
    constructor(valueGenerator: T) {
        this.generator = valueGenerator;
    }

    next(): Array<ReturnType<T['next']>> {
        return [this.generator.next()];
    }
}

const numGenerator = new NumberGenerator();
const fn1 = <T extends ValueGenerator>(t: T) => new ArrayGenerator(t);
const fn2 = (...args: ConstructorParameters<typeof ArrayGenerator>) => new ArrayGenerator(...args)
const generator1 = fn1(numGenerator);
const generator2 = fn2(numGenerator);

// number[]
const a = generator1.next();
// any[]
const b = generator2.next();

有没有一种方法可以为ArrayGenerator创建工厂函数而无需像我对fn1那样手动编写正确的签名?理想情况下,我想做类似fn2的操作,但是它不能按预期工作。 fn2将正确推断构造函数参数,但不会推断generator2.next返回类型。

1 个答案:

答案 0 :(得分:1)

如果您手动编写一个函数,我认为编译器将不会为您推断出通用函数。但是,TypeScript 3.4引入了support for higher order type inference in generic functions,TypeScript 3.5之后是the corresponding support for generic constructor functions。这使您可以编写一个通用的高阶函数,该函数接受一个函数并返回一个函数,并且如果输入是通用的,则编译器将尝试自动使输出通用。推理算法并不完美,但是对于我在这里想要做的事情来说已经足够了,这就是创建一个通用的“从构造函数到工厂”的功能:

function ctorToFactory<A extends any[], R>(ctor: new (...args: A) => R): (...args: A) => R {
    return (...args) => new ctor(...args);
}

如果您在ArrayGenerator上调用它,则会自动获得一个通用的fn2,而无需自己输入:

const fn2 = ctorToFactory(ArrayGenerator);
// const fn2: <T extends ValueGenerator>(valueGenerator: T) => ArrayGenerator<T>
const generator2 = fn2(numGenerator);
const b = generator2.next(); // number[]

好的,希望能有所帮助;祝你好运!

Link to code