I'm trying two different classes in Typescript playground that implement the same interface. I can't figure out why a method speak() with void return type in the interface doesn't trigger an error if it's implementation returns something other than void.
I have to explicitly implement the method with a return type void to trigger the type-checking. This doesn't seem to happen for return types other than void, as shown below.
Snippet in Typescript Playground
interface Person {
speak(): void;
walk(): number;
}
export class HumanOne implements Person {
speak() {
return 'Hello'; // No type error
}
walk() {
return 'Walking'; // Type error
}
}
export class HumanTwo implements Person {
speak(): void {
return 'Hello'; // Type error
}
walk(): number {
return 'Walking'; // Type error
}
}
The inferred type of the method without the explicit type declaration is HumanOne.speak(): string. This is compatible with void, which has two meanings:
void, it means that it doesn't return anything, more or less equivalent to specifying undefined as a return type.void means that anything can be returned, and that the return value of calls must not be used. It's more or less equivalent to unknown as far as type compatibility is concerned (but unlike unknown, you can't really pass around values of type void).This second meaning is also what is relevant for the subtype checking of HumanOne implements Person - the type () => string is a subtype (or: assignable to) type () => void. If you call Person.speak(), you must ignore the return value (and it might be undefined, a string, or anything else); if you call HumanOne.speak() you'll know that you get a string back.
This is very much by design, see the docs on Return type void and the FAQ entry "Why are functions returning non-void assignable to function returning void?".