TypeScript:使通用接口 A<T> 的方法仅在 T 是某种类型时可用

TypeScript: make a method of a generic interface A<T> available only if T is of a certain type

请看这段代码:

interface A<T> {
    method1(): A<T>;
}

interface B<T extends Function> extends A<T> {
    method2(): B<T>;
}

var foo: A<Function>;
foo.method1();
foo.method2();

我希望 fooB<Function> 类型兼容,但我却得到 error TS2339: Property 'method2' does not exist on type 'A<Function>'。我可以重写接口 B 以使其正常工作吗?

实际上,我正在尝试修复 lodash 的 _.memoize:

的类型
// This should be OK. The type of result1 should be compatible with aFunction.
var result1 = _(aFunction).memoize().value();

// And this should be an error.
var result2 = _(aNonFunctionValue).memoize().value();

UPDATE. 基本上,我的问题是:我可以为 A<T> 编写这样一个通用方法,只有在 T 是其他类型的子类型 U?

Can I rewrite the interface B somehow to get it to work?

解决方案

代码如下:

interface A<T> {
    method1(): A<T>;
}

interface B<T extends Function> extends A<T> {
    method2(): B<T>;
}

interface A<T> {
    method2<T extends Function>(): B<T>;
}

var foo: A<Function>;
foo.method1();
foo.method2(); // works!

找到解决方案

让我们退后一步,想想我们想要做什么

var foo: A<Function>;
foo.method2(); // Should work

这意味着 A<Function> 上应该有 method2。所以:

interface A<T> {
    method2<T extends Function>(): B<T>;
}

并且此方法二在 T 和 returns 类型 B 上添加了通用约束。

剩下的在最终的解决方案中就清楚了

原来 TypeScript 不支持这个。参见 https://github.com/Microsoft/TypeScript/issues/1290

2019 年更新: 现在我们有 Conditional Types,这是小菜一碟:

interface A<T> {
    method1(): A<T>;
    method2: T extends Function ? () => A<T> : never;
}

declare var foo: A<Function>;
foo.method1();
foo.method2();