考虑以下通用接口:
现在假设我实例化了
interface Extractor<T> {
extractCandidate(): T;
process(candidate: T): T;
}
概念上,每个Extractor
实现负责从某个数据源中提取特定类型的对象。 Extractor
的使用者可以使用extractCandidate()
提取候选对象,或者在给定任何候选对象的情况下,使用process()
对其进行进一步处理以获得更精细的对象版本。
现在,假设我为类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 的结构类型系统有关,但在阅读了 some related questions 和 FAQ 后,我仍然不确定它如何具体应用于此处。
我的Typescript版本是2.1.4。
candidate
上指定类型约束吗?在MyExtractor
中,T
是MyClass
,那么为什么candidate
可以是其他任何类型?实际上,如果我断言candidate
的类型是string
并返回一个空字符串,我会得到我期望的错误:"类型'(candidate: string) => string'不能赋值给类型'(candidate: MyClass) => MyClass'。参数'candidate'和'candidate'的类型不兼容。类型'MyClass'不能赋值给类型'string'。" - ethan.rodayprocess(candidate)
类型化为process(candidate: MyClass): MyClass
,那就太好了。我曾经遇到过类似的困惑,因为React组件定义指定了成员的类型,但实际上你可以使用不正确的类型进行实现,最终还是要在实现中给它正确的类型。 - Aaron BeallMyClass
参数并不意味着实现不能处理其他东西,这就是编译器不会做出这种假设的原因。为了避免这个“问题”,只需使用noImplicitAny
,然后你就会知道何时/在哪里有这些情况。 - Nitzan Tomer