打字稿:实现通用接口

Typescript: Implementing a generic interface

考虑以下通用接口:

interface Extractor<T> {
  extractCandidate(): T;
  process(candidate: T): T;
}

从概念上讲,每个 Extractor 实现负责从某些数据源中提取特定类型的对象。 Extractor 的消费者可以使用 extractCandidate() 提取候选对象,或者,给定任何候选对象,使用 process().[= 对其执行一些进一步的处理以获得更精确的对象版本。 27=]

现在,假设我为 class MyClass 实现了 Extractor,如下所示:

class MyClass {
  a: string;
  b: string;
}

class MyExtractor implements Extractor<MyClass> {
  extractCandidate() {
    //Some dummy logic
    return new MyClass();
  }
  process(candidate) {
    //Some dummy logic
    let res = new MyClass();
    res.a = candidate.a;
    return res;
  }
}

现在假设我实例化 MyExtractor 并使用它:

let myExtractor = new MyExtractor();
let processed = myExtractor.process('blah');

问题 1:为什么这不会产生编译时错误?根据 Extractor 接口的定义,我希望编译器不允许我用 MyClass 的实例以外的任何东西调用 myExtractor.process(),或者至少用结构上的东西兼容。

问题 2:如何强制执行所需的行为?我是否只需要断言 MyExtractor.process()candidate 参数是 MyClass 类型?

我怀疑这与 TypeScript 的结构类型系统有关,但在阅读 questions and the FAQ 之后,我仍然不确定它在这里的具体应用。

我的 Typescript 版本是 2.1.4。

您为 MyExtractor 发布的代码具有以下 process 方法的签名:

process(candidate: any): MyClass

原因是您没有为 candidate 指定类型,所以默认情况下它是 any
编译器不会报错,因为它满足 candidate: T(因为 any 可以是 T)。

如果您将代码更改为:

process(candidate: MyClass) {
    ...
}

然后为:

let processed = myExtractor.process('blah');

您将获得:

Argument of type '"blah"' is not assignable to parameter of type 'MyClass'

您可以通过使用 --noImplicitAny flag 来避免这种情况,这会导致编译器抱怨:

process(candidate) {
    ...
}

说:

Parameter 'candidate' implicitly has an 'any' type


编辑

不允许候选 "anything else",允许 any(这是默认值),例如,一个很好的理由是重载:

process(candidate: string): MyClass;
process(candidate: MyClass): MyClass;
process(candidate: any) {
    ...
}