为什么在实现通用接口时TypeScript无法推断函数参数的类型?

Mar*_*ell 4 generics typescript

我正在Visual Studio 2015中编写TypeScript,安装了语言服务扩展版本2.3.3.0。我在项目的中noImplicitAny设置了参数。truetsconfig.json

给出以下简单的示例代码:

interface ITransformer<TInput, TOutput> {
    transform(input: TInput): TOutput;
}

class Input {
    name: string;
}

class Output {
    name: string;

    constructor(name: string) {
        this.name = name;
    }
}

class Test {
    name: string;
}

class Transformer implements ITransformer<Input, Output> {
    transform = (input) => new Output(input.name);
}
Run Code Online (Sandbox Code Playgroud)

TS编译器给我一个错误TS7006: Parameter 'input' implicitly has an 'any' type

在此处输入图片说明

现在,我可以通过向input参数添加类型注释来轻松修复此错误:

class Transformer implements ITransformer<Input, Output> {
    transform = (input: Input) => new Output(input.name);
}
Run Code Online (Sandbox Code Playgroud)

但是我的问题是,为什么我必须这样做?在我看来,该参数的类型应该从TInput接口的实现中推断出来(在这种情况下为Input)。

更令人担忧的是,我可以高兴地做到这一点:

class Transformer implements ITransformer<Input, Output> {
    transform = (input: Test) => new Test();
}
Run Code Online (Sandbox Code Playgroud)

它接受并返回一个完全不同的类型,而这两个类型参数都未引用该类型,并且编译器似乎对此没有问题...

来自C#背景,这似乎是错误的。我想念什么?

Nit*_*mer 5

实施ITransformer接口时,可以transform使用不同的签名覆盖,例如:

class Transformer implements ITransformer<Input, Output> {
    transform(input: string): Output;
    transform(input: number): Output;
    transform(input: Input): Output;
    transform(input: any): Output {
        // ...
    }
}
Run Code Online (Sandbox Code Playgroud)

您不必只在接口中实现签名的实现。因此,您必须隐式地编写类型:

transform = (input: Input) => new Output(input.name);
Run Code Online (Sandbox Code Playgroud)

至于为什么这样工作:

transform = (input: Test) => new Test();
Run Code Online (Sandbox Code Playgroud)

这是因为TypeScript基于结构子类型,并且两种类型具有相同的结构({ name: string })。尝试将另一个属性添加到其中一个中,您将得到一个错误。

我要指出的最后一件事是,定义类方法的方式实际上不会创建方法,而只会创建具有函数类型的成员:

class Test {
    method1() { }

    method2 = () => {}
}
Run Code Online (Sandbox Code Playgroud)

这只是method1一个真正的方法,而method2只是在构造函数中分配的属性,它不会成为原型的一部分,并且如果扩展类,将无法覆盖它。

这是此代码的编译版本:

var Test = (function () {
    function Test() {
        this.method2 = function () { };
    }
    Test.prototype.method1 = function () { };
    return Test;
}());
Run Code Online (Sandbox Code Playgroud)

这种方法很好并且正在使用,但是请注意。