The title says it all. I don't understand the specific effects of choosing the first or the second way to declare the signature of a function
interface Human {
firstName : string;
age: number;
greet:()=> void;
}
and
interface Human {
firstName : string;
age: number;
greet():void;
}
I hope you can clarify this for me.
Thanks guys
CodePudding user response:
One is a field that happens to be a function, the other is a method. This might not seem like a big deal at first (for interfaces), and in most cases it is not. There is however a subtle difference between the two, namely variance.
Parameters for function signatures are contra-variant, while for methods parameters they are bi-varaint. This comes into play when checking compatibility between types and when implementing the interface.
Now in your case since you don't actually have any parameters, this has no impact, but it you were to have a parameter, this can become importat:
{
interface Human {
greet: (p: string | null) => void;
}
class HumanImpl implements Human {
greet(p: string) { // Error Types of parameters 'p' and 'p' are incompatible.
}
}
}
{
interface Human {
greet(p: string | null): void;
}
class HumanImpl implements Human {
greet(p: string) { // This is fine for methods
return "Hi" p.toUpperCase() // p is never null, right?
}
}
let h: Human = new HumanImpl();
h.greet(null) // wops, runtime error on type cheched code
}
For more about variance see my talk
The reason for this loophole is that with strict variance for methods, most types (and importantly Array
) would become invariant as explained in this PR
Note: For classes there is an added discussion as to if the function is on the instance or the prototype, but this does not come into play for interfaces.