What is the difference between the type inference of foo1
and foo2
in the code given below:
interface myInterface {
foo1(args: string): void;
foo2: (args: string) => void;
}
Is type inference different for both? Also when to use which one?
Since regular functions are constructible, they can be called using the new keyword. However, the arrow functions are only callable and not constructible, i.e arrow functions can never be used as constructor functions. Hence, they can never be invoked with the new keyword.
arguments object inside the regular functions contains the list of arguments. The arrow function, on the opposite, doesn't define arguments (but you can easily access the arrow function arguments using a rest parameter ... args ).
The takeaway: Function expressions are best for object methods. Arrow functions are best for callbacks or methods like map, reduce, or forEach. You can read more about scopes on MDN. On a fundamental level, arrow functions are simply incapable of binding a value of this different from the value of this in their scope.
Arrow functions don't have access to the new.target keyword. Arrow functions aren't suitable for call , apply and bind methods, which generally rely on establishing a scope. Arrow functions cannot be used as constructors. Arrow functions cannot use yield , within its body.
In interfaces, there is almost no difference. You can mix and match both styles, according to your preferences:
interface myInterface {
foo1(args: string): void;
foo2: (args: string) => void;
}
class C implements myInterface {
foo1: (args: string) => void = (args) => {
}
foo2(args: string) {
}
}
Also, both are completely interchangeable at runtime:
declare const i: myInterface;
const c = new C;
// no errors
c.foo1 = i.foo2;
i.foo1 = c.foo2;
c.foo2 = i.foo1;
i.foo2 = c.foo1;
There is one difference affecting type inference: --strictFunctionTypes flag does not apply to methods, so in strict mode methods and function properties have different compatibility rules when their argument and return types are not identical.
Another difference is that you can declare property read-only, to prevent assigning to it. You can't do that with a method (but still, you can declare another type with Readonly<myInterface>
which will have all properties and methods read-only).
interface myInterface {
foo1(args: string): void;
readonly foo2: (args: string) => void;
}
i.foo2 = c.foo1; // this is an error now
However, in classes, they are different, probably because methods are defined on class prototype objects at runtime, but properties are initialized in the code generated for the constructor, so it's impossible to override property with a method:
class C2 extends C {
foo1(args: string) { // error: Class 'C' defines instance member property 'foo1',
// but extended class 'C2' defines it as instance member function.
}
foo2: (args: string) => void = (args) => { // Ok
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With