Reputation: 127
interface Foo {
fn1(x: string): void;
}
class Test implements Foo {
public fn1 (): string {
return "111"
}
}
Expected got an error like: Class Test incorrectly implements interface Foo
Because the function's signature was incorrect
Without luck. There was no any error for show
Upvotes: 7
Views: 1179
Reputation: 6809
Typescript uses structural typing to determine type compatibility. For functions this means that you don't need to have the exact same signature for the declaration and the implementation, as long as the compiler can determine the implementation to be safe to call through the declaration.
Consider example in this way way,
interface Foo {
fn1(x: string): void;
}
class Test implements Foo {
constructor()
{}
public fn1 (): string {
return "111"
}
}
const fn1: Foo = new Test(); // error, fn1 has parameter, although Test fn1 doesn't expect one
const fn2: Test = new Test();
The reason you get an error on fn1
but not fn2
is because once the assignment is done the compiler only knows the type of the variable not what you originally assigned into it and will check based on the actual type of the variable. So for fn1
this means Foo.fn1
requires a parameter, no way to know it does not. For fn2
it will check Test.fn1
which is known to require no arguments.
This how how can try to safeguard your types in Typescript.
Upvotes: 2
Reputation: 51034
This isn't actually an incorrect signature. It can be called with a single argument as a string, and it will just ignore that argument. Keep in mind that this is how Javascript works, and Typescript compiles to Javascript:
function bar() {
console.log('bar');
}
bar('baz'); // no error at runtime in Javascript
Likewise, the interface's signature says the method is void, and that's compatible with the method actually returning a string. If the caller thinks it's void then they'll never observe it return a string. Nobody would write the following if they thought obj.fn1()
didn't return anything:
let result = obj.fn1(); // why am I assigning the return value of a void method?
So, despite having the "wrong" parameter and return types, the method can in fact be used safely as if it takes a string and returns nothing, so it's compatible with the interface's signature.
That's all well and good, but Typescript could have been designed to report an error here, and an error message might have been helpful in your example. But there are many cases where it would not be helpful. Consider this code:
let names = ['Alice', 'Bob', 'Clive'];
let counts: Record<string, number> = {};
names.forEach(name => counts[name] = 0);
The signature of Array.prototype.forEach
says that callbackfn
's type should be:
(value: any, index: number, array: any[]) => void
But the arrow function's type is (name: string) => number
. This has fewer parameters and a non-void return type. So it would be exactly the same "error" as in your example. Of course, this is a basic and correct usage of forEach
, and it would not be helpful for Typescript to complain about it.
Upvotes: 6