ashe
ashe

Reputation: 127

No error when typescript class implements interface method with incorrect signature

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

Answers (2)

Sohan
Sohan

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

kaya3
kaya3

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

Related Questions