打字稿:实现通用接口
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) {
...
}
考虑以下通用接口:
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 的结构类型系统有关,但在阅读
我的 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) {
...
}