如何在打字稿中专门化通用 class 的模板类型?

How to specialize template type of a generic class in typescript?

是否可以在 typescript 中的泛型函数中特化泛型 class 的模板类型?

假设我有一个通用接口和一个将接口构造函数作为参数的函数:

interface IA<T> {
    func(arg: T)
}

function g<T, IAType extends IA<T>>(
    constructor: { new(): IAType }
): (arg: T) => IAType {
    const ins = new constructor();
    return arg => {
        ins.func(arg);
        return ins;
    }
}

然后我提供class实现IA<T>,也就是

class A implements IA<{ key: string }> {
    func(arg: { key: string }) {
        console.log(arg.key);
    }
}

const t = g(A); // type of t is (arg: {}) => A

如何编写函数 g 或 class A 以便函数 g 可以根据传入的参数专门化正确的模板类型?我想要最终的 t 具有类型 (arg: {key: string}) => A

此类型用于 constructor 参数用于 g

 constructor: { new(): IAType }

并没有真正施加约束,即 IAType 中的 func() 必须具有 T 作为其参数类型。唯一的约束是 IAType extends IA<T>,这意味着 IAType 中的 func 可以是任何类型,只要它与 func(arg: T) 兼容。推理算法可能从最小类型开始,即 {},验证 func(arg: {})func(arg: T) 兼容并就此停止。

constructor 类型更加严格有助于:

interface IA<T> {
    func(arg: T): void
}

function g<T, IAType extends IA<T>>(
    constructor: { new(): IA<T> & IAType }
): (arg: T) => IAType {
    const ins = new constructor();
    return arg => {
        ins.func(arg);
        return ins;
    }
}

class A implements IA<{ key: string }> {
    func(arg: { key: string }) {
        console.log(arg.key);
    }
}

const t = g(A); // type of t is (arg: { key: string; }) => A

两个IA<T> & IAType都是必须的。如果您只有 IA<T>arg 类型将根据需要进行推断,但 return 类型将只有 IA<T>,而不是 A.