网站搜索

TypeScript:仅当 T 是某种类型时,使泛型接口 A 的某个方法可用


请看这段代码:

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();

我本以为 foo 可以与 B<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();

更新。 基本上,我的问题是:我能否为 A<T> 编写这样一个通用方法,使其仅在 T 是某个其他类型 U 的子类型时可用?

答案#1

我能以某种方式重写接口 B 以使它工作吗?

解决方案

这是代码:

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 增加了一个通用约束,并返回 B 类型的内容。

其余的在最终解决方案中很清楚 🌹

答案#2

结果 TypeScript 不支持这个。请参见 https://github.com/Microsoft/TypeScript/issues/1290

2019 更新:现在我们有了条件类型,这简直轻而易举:

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

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