首页 > 解决方案 > TypeScript - 如何从方法的参数推断类泛型类型?

问题描述

我正在尝试从稍后将调用的方法参数键入一个泛型类。直到我们调用一个带有泛型参数的方法,类的泛型类型才会被知道。然后,对于任何其他方法,泛型类型将被传递。

老实说,对我来说,这似乎功能如此复杂,以至于我什至不确定 TypeScript 是否有办法做到这一点......

这是我希望行为看起来的样子:

class Class<T> {
    foo = (bar: T[]) => {
        /* ... */
        return this;
    };

    baz = (cb: (qux: T) => void) => {
        /* ... */
        return this;
    };
}

new Class() // Here, T should be unknown
    .foo([{ name: "John", id: "123" }]) // Here, it should be infered that T is { name: string, id: string }
    .baz((person) => null) // Here, person should have the type { name: string, id: string }

在这个例子中,当我们实例化 时ClassT应该是未知的。然后,当我们将对象数组传递给 时fooT应该推断 是该对象类型,因为bar是 typed T[]。现在T已经推断出,qux在将函数传递给baz. ( baz(cb: ({ name: string, id: string }) => void))

请注意,我不想将泛型传递给Class我希望稍后推断它。换句话说,我不想

new Class<{ name: string, id: string }>()

感谢您的回答!

标签: typescriptclassgenerics

解决方案


我猜写这个问题就像是橡皮鸭调试!在我发帖后大约几分钟,我发现了这个。然而,它不是太漂亮,所以我将把线程打开一段时间,以防出现更好的主意:

class Class<T> {
    foo = <U extends T>(bar: U[]) => {
        /* ... */
        return (this as unknown) as Class<U>; // not pretty
    };

    baz = <U extends T>(cb: (qux: U) => void) => {
        /* ... */
        return (this as unknown) as Class<U>; // not pretty
    };
}

new Class() // Here, T is unknown, as it should be
    .foo([{ name: "John", id: "123" }]) // Here, T becomes U ({name: string, id: string})
    .baz((person) => null); // Here, person is typed {name: string, id: string} Yay!

// This also works!
new Class() // Here, T is unknown, as it should be
    .baz((person: { name: string; id: string }) => null) // Here, T becomes U ({name: string, id: string})
    .foo([{ name: "John", id: "123" }]); // Here, bar is typed { name: string, id: string }[] Yay again!

通过使用扩展类的泛型类型的另一种泛型类型键入方法,我们可以返回this并“安全地”键入它作为Class<U>,现在它给出了一个实际类型而不是unknown

这里的问题是,这仅适用于我们在this使用新类型输入时返回Class<U>。因此,将对象传递给不返回的方法this不会修改它的泛型类型......

class Class<T> {
    public data: T;

    quux = <U extends T>(quuz: U) => {
        this.data = quuz;
        /* ... void */
    };
}

const c = new Class();
c.quux({ name: "John", id: "123" });
c.data // still unknown

推荐阅读