Consider the following generic interface:
interface Extractor<T> {
extractCandidate(): T;
process(candidate: T): T;
}
Conceptually, each Extractor
implementation is responsible for extracting a particular kind of object from some datasource. The consumer of the Extractor
can extract a candidate object using extractCandidate()
or, given any candidate, perform some further processing on it to get a more refined version of the object using process()
.
Now, let's say I implement an Extractor
for a class MyClass
, like so:
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;
}
}
Now let's say I instantiate MyExtractor
and use it:
let myExtractor = new MyExtractor();
let processed = myExtractor.process('blah');
Question 1 : Why does this not generate a compile-time error? Based on the definition of the Extractor
interface, I would expect that the compiler would not allow me to call myExtractor.process()
with anything but an instance of MyClass
, or at least with something that is structurally compatible.
Question 2 : How can I enforce the desired behavior? Do I just need to assert that the candidate
parameter of MyExtractor.process()
is of type MyClass
?
I suspect this has something to do with TypeScript's structural typing system but, after reading some related questions and the FAQ , I'm still not sure how it specifically applies here.
My Typescript version is 2.1.4.
The code you posted for MyExtractor
has the following signature for the process
method:
process(candidate: any): MyClass
The reason for that is that you haven't specified a type for candidate
so by default it is any
.
The compiler won't complain because it satisfies candidate: T
(as any
can be T
).
If you change your code to:
process(candidate: MyClass) {
...
}
Then for:
let processed = myExtractor.process('blah');
You'll get:
Argument of type '"blah"' is not assignable to parameter of type 'MyClass'
You can avoid that by using the --noImplicitAny flag which will cause the compiler to complain about:
process(candidate) {
...
}
Saying:
Parameter 'candidate' implicitly has an 'any' type
Candidate isn't allowed to be "anything else", it is allowed to be any
(and that's the default), a good reason for that for example is for overloading:
process(candidate: string): MyClass;
process(candidate: MyClass): MyClass;
process(candidate: any) {
...
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.