TypeScript Function Types

May 17, 2023#typescript

In TypeScript, functions are values that can be assigned to variables, passed as arguments, or returned from other functions. To specify the type of a function, you can use a function type, which describes the parameters and the return value of the function.

There are different ways to write function types in TypeScript, depending on the context and the purpose. Here are some examples:

Function type expressions

These are types that use the arrow syntax (parameter: type) => type to specify the function type. For example, (a: string) => void means a function that takes a string parameter and returns nothing. You can use function type expressions to annotate variables that hold functions or parameters that expect functions.

// Optional Parameters and Default Values
type GreetingFunction = (name?: string) => void;

const greet: GreetingFunction = (name = 'Guest') => {
  console.log(`Hello, ${name}!`);
};

greet(); // Output: Hello, Guest!
greet('John'); // Output: Hello, John!

Call signatures

These are types that use an object type with a call signature property to specify the function type. A call signature has the syntax (parameter: type): type. For example, {(a: string): void} means an object that can be called as a function with a string parameter and returns nothing. You can use call signatures to describe functions that have additional properties besides being callable.

type DescribableFunction = {
  description: string;
  (someArg: number): boolean;
};

const isOdd = Object.assign (
  (someArg: number) => someArg % 2 === 1,
  { description: "isOdd" }
);

function isPrime (someArg: number) {
  // some logic to check if someArg is prime
  return true;
}
isPrime.description = "isPrime";

function doSomething (fn: DescribableFunction) {
  console.log (fn.description + " returned " + fn(6));
}

doSomething(isOdd); // logs "isOdd returned false"
doSomething(isPrime); // logs "isPrime returned true"

Construct signatures

These are types that use an object type with a construct signature property to specify the function type. A construct signature has the syntax new (parameter: type): type. For example, {new (s: string): Date} means an object that can be invoked with the new operator with a string parameter and returns a Date object. You can use construct signatures to describe constructors or factory functions.

class SomeObject {
  constructor (public s: string) {}
}

type SomeConstructor = {
  new (s: string): SomeObject;
};

const someConstructor: SomeConstructor = SomeObject;
const someObject = new someConstructor("hello"); // OK

Construct signatures are mainly used when defining types for external JavaScript libraries that are not written in TypeScript. They allow you to specify how to create objects from those libraries using new. However, you can also use them for passing classes around as parameters or return values.

Generic functions

These are functions that can work with different types of values based on type parameters. You can write generic functions by declaring one or more type parameters in the function signature using angle brackets <T>. For example, <T>(arr: T[]) => T means a function that takes an array of any type T and returns an element of type T. You can use generic functions to write reusable and flexible code.

// A generic function
function firstElement<T>(arr: T[]): T {
  return arr[0];
}

// Using the generic function with different types
let s = firstElement(["a", "b", "c"]); // s is of type string
let n = firstElement([1, 2, 3]); // n is of type number