The inferred type of the method without the explicit type declaration is HumanOne.speak(): string
. This is compatible with void
, which has two meanings:
- in a function implementation with return type
void
, it means that it doesn’t return anything, more or less equivalent to specifyingundefined
as a return type. - in a function type declaration,
void
means that anything can be returned, and that the return value of calls must not be used. It’s more or less equivalent tounknown
as far as type compatibility is concerned (but unlikeunknown
, you can’t really pass around values of typevoid
).
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?“.