网站搜索

如何在 TypeScript 中专门化泛型类的模板类型?


在 typescript 中,是否可以在泛型函数中专门化泛型类的模板类型?

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

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;
    }
}

然后我提供这个类实现了 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 或类 A,以便函数 g 可以根据传入的参数专门化正确的模板类型?我希望最终的 t 的类型是 (arg: {key: string}) => A

答案#1

这是 g 的 constructor 参数的类型

 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 的类型将会按预期推断,但返回类型将仅是 IA<T>,而不是 A。