Build a function object with properties in TypeScript Build a function object with properties in TypeScript typescript typescript

Build a function object with properties in TypeScript


Update: This answer was the best solution in earlier versions of TypeScript, but there are better options available in newer versions (see other answers).

The accepted answer works and might be required in some situations, but have the downside of providing no type safety for building up the object. This technique will at least throw a type error if you attempt to add an undefined property.

interface F { (): any; someValue: number; }var f = <F>function () { }f.someValue = 3// type errorf.notDeclard = 3


This is easily achievable now (typescript 2.x) with Object.assign(target, source)

example:

enter image description here

The magic here is that Object.assign<T, U>(t: T, u: U) is typed to return the intersection T & U.

Enforcing that this resolves to a known interface is also straight-forward. For example:

interface Foo {  (a: number, b: string): string[];  foo: string;}let method: Foo = Object.assign(  (a: number, b: string) => { return a * a; },  { foo: 10 }); 

which errors due to incompatible typing:

Error: foo:number not assignable to foo:string
Error: number not assignable to string[] (return type)

caveat: you may need to polyfill Object.assign if targeting older browsers.


TypeScript is designed to handle this case through declaration merging:

you may also be familiar with JavaScript practice of creating a function and then extending the function further by adding properties onto the function. TypeScript uses declaration merging to build up definitions like this in a type-safe way.

Declaration merging lets us say that something is both a function and a namespace (internal module):

function f() { }namespace f {    export var someValue = 3;}

This preserves typing and lets us write both f() and f.someValue. When writing a .d.ts file for existing JavaScript code, use declare:

declare function f(): void;declare namespace f {    export var someValue: number;}

Adding properties to functions is often a confusing or unexpected pattern in TypeScript, so try to avoid it, but it can be necessary when using or converting older JS code. This is one of the only times it would be appropriate to mix internal modules (namespaces) with external.