Function property vs method

If these are the only declarations, these are identical.

The only difference is that you can augment the first form in a second declaration to add new signatures:

// Somewhere
interface Foo {
  bar(): void;
}

// Somewhere else
interface Foo {
  bar(s: number): void;
}

// Elsewhere
let x: Foo = ...
x.bar(32); // OK

There is another difference, in that the readonly modifier cannot be applied to methods. Therefore, the following assignment cannot be prevented:

interface Foo {
    bar(): void;
}

declare var x: Foo;
x.bar = function () { };

If bar is defined as a property, then the readonly modifier can be applied to it:

interface Foo {
    readonly bar: () => void;
}

preventing reassignment.

(Playground)


The most critical difference is actually that using the property approach typescript actually checks contravariently for types. For Eg:

type FProp<A> = {
  fork: (a: A) => void  
}
type FMeth<A> = {
  fork(a: A): void  
}

type Cat = {
  isPurring: boolean
}

type Dog = {
  isBarking: boolean
}


const dd = { fork: (a: Cat & Dog) => void 0 }

const fa: FProp<Cat> = dd // will throw up
const fb: FMeth<Cat> = dd // will not issue any error

This is documented —

The stricter checking applies to all function types, except those originating in method or constructor declarations. Methods are excluded specifically to ensure generic classes and interfaces (such as Array) continue to mostly relate covariantly.

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html


It seems that the compiler doesn't seem to care, as all of these are valid:

interface Foo1 {
    bar(): void;
}

class Foo1Class1 implements Foo1 {
    bar = () => { }
}

class Foo1Class2 implements Foo1 {
    bar() { }
}

interface Foo2 {
    bar: () => void;
}

class Foo2Class1 implements Foo2 {
    bar = () => { }
}

class Foo2Class2 implements Foo2 {
    bar() { }
}

(code in playground)

The reason for that is probably to do with how that compiles into javascript:

var Foo1Class1 = (function () {
    function Foo1Class1() {
        this.bar = function () { };
    }
    return Foo1Class1;
}());
var Foo1Class2 = (function () {
    function Foo1Class2() {
    }
    Foo1Class2.prototype.bar = function () { };
    return Foo1Class2;
}());

In both cases an instance of one of those classes will have a property named bar which is a callable function.
The difference is only that in Foo1Class2 the bar method is part of the prototype which can then be overriden by an extending class.