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
}
}