Callable

You can annotate callables as a part of a type or an interface as follows

  1. interface ReturnString {
  2. (): string
  3. }

An instance of such an interface would be a function that returns a string e.g.

  1. declare const foo: ReturnString;
  2. const bar = foo(); // bar is inferred as a string

Obvious examples

Of course such a callable annotation can also specify any arguments / optional arguments / rest arguments as needed. e.g. here is a complex example:

  1. interface Complex {
  2. (foo: string, bar?: number, ...others: boolean[]): number;
  3. }

An interface can provide multiple callable annotations to specify function overloading. For example:

  1. interface Overloaded {
  2. (foo: string): string
  3. (foo: number): number
  4. }
  5. // example implementation
  6. function stringOrNumber(foo: number): number;
  7. function stringOrNumber(foo: string): string;
  8. function stringOrNumber(foo: any): any {
  9. if (typeof foo === 'number') {
  10. return foo * foo;
  11. } else if (typeof foo === 'string') {
  12. return `hello ${foo}`;
  13. }
  14. }
  15. const overloaded: Overloaded = stringOrNumber;
  16. // example usage
  17. const str = overloaded(''); // type of `str` is inferred as `string`
  18. const num = overloaded(123); // type of `num` is inferred as `number`

Of course, like the body of any interface, you can use the body of a callable interface as a type annotation for a variable. For example:

  1. const overloaded: {
  2. (foo: string): string
  3. (foo: number): number
  4. } = (foo: any) => foo;

Arrow Syntax

To make it easy to specify callable signatures, TypeScript also allows simple arrow type annotations. For example, a function that takes a number and returns a string can be annotated as:

  1. const simple: (foo: number) => string
  2. = (foo) => foo.toString();

Only limitation of the arrow syntax: You can’t specify overloads. For overloads you must use the full bodied { (someArgs): someReturn } syntax.

Newable

Newable is just a special type of callable type annotation with the prefix new. It simply means that you need to invoke with new e.g.

  1. interface CallMeWithNewToGetString {
  2. new(): string
  3. }
  4. // Usage
  5. declare const Foo: CallMeWithNewToGetString;
  6. const bar = new Foo(); // bar is inferred to be of type string