Why does TypeScript track mutation of function static properties?

Starting with TypeScript 3.1, you are allowed to define “expando” properties on functions. This was implemented in microsoft/TypeScript#26368 as a fix to microsoft/TypeScript#15868. Apparently there are common patterns where developers add properties to functions in JavaScript, but before this feature there was no idiomatic way to do this in TypeScript.

Right now you can do this:

function foo(x: string) { foo.callCount++; return x.length }
foo.callCount = 0;

But before TypeScript 3.1 you had to do something like this:

function bar(x: string) { bar.callCount++; return x.length }
namespace bar {
  export var callCount = 0;
}

or this:

const baz = Object.assign(
  (x: string) => { baz.callCount++; return x.length },
  { callCount: 0 }
);

or even this:

const qux = ((x: string) => { qux.callCount++; return x.length }) as
  { (x: string): number; callCount: number };
qux.callCount = 0;

all of which were fairly ugly.


While it might be nice to allow expando properties on all objects (like DescribableObject) and not just functions, as requested in microsoft/TypeScript#12416, it seems that this is not as common or important a pattern to support. Generally speaking you can use an object literal to add all the properties you want at once (although sometimes dependencies can be difficult to deal with) but you can’t do that with a function.

Playground link to code

Leave a Comment