Question

Get a Function Return Type in TypeScript with ReturnType

typescripttypescript1.8

Question

Given this TypeScript function:

function test(): number {
  return 42;
}

Using typeof test produces the function type () => number:

type T = typeof test;

How can you obtain only the function's return type, so that the resulting type is number rather than () => number?

Short Answer

You can extract a function's return type in TypeScript with the built-in ReturnType<T> utility type. Combine it with typeof when starting from a named function:

type Result = ReturnType<typeof test>; // number

By the end, you will know the difference between a function type and its result type, and how to reuse return types safely in real code.

Concept

typeof and ReturnType answer two different questions in TypeScript.

  • typeof test asks: What is the type of the function value named test?
  • ReturnType<typeof test> asks: What type does that function produce when called?

For example:

function test(): number {
  return 42;
}

type FunctionType = typeof test;             // () => number
type TestResult = ReturnType<typeof test>;   // number

ReturnType<T> is a built-in utility type. It accepts a function type and extracts the type after the function's arrow, such as number in () => number.

This matters because return types are often shared. For example, a helper may create an object that another function, state variable, or API handler needs to use. Deriving the type avoids manually writing the same object shape in multiple places.

Mental Model

Think of a function as a vending machine.

  • typeof test describes the whole machine: it takes no input and dispenses a number. Its type is () => number.
  • ReturnType<typeof test> describes only the item that comes out: a number.

typeof gives you the machine's instruction label. ReturnType reads that label and picks out the output.

Take Quiz

Syntax and Examples

Use ReturnType with a function type.

type ReturnType<T extends (...args: any[]) => any> = /* built in */;

In normal code, you do not define it yourself. Use TypeScript's built-in version:

function test(): number {
  return 42;
}

type T = ReturnType<typeof test>;
// T is number

For a function type written directly, pass that type to ReturnType:

type Formatter = (value: string) => string;
type FormattedValue = ReturnType<Formatter>;
// FormattedValue is string

It also works well with functions that return objects:

function createUser(name: string) {
  return {
    id: crypto.randomUUID(),
    name,
    active: true,
  };
}

type User = ReturnType<typeof createUser>;
// { id: string; name: string; active: boolean }

Step by Step Execution

Consider this example:

function calculateTotal(price: number, quantity: number): number {
  return price * quantity;
}

type Calculator = typeof calculateTotal;
type Total = ReturnType<typeof calculateTotal>;

TypeScript evaluates the type aliases as follows:

  1. calculateTotal is a function that accepts two number arguments.

  2. It returns a number.

  3. typeof calculateTotal becomes the full function type:

    (price: number, quantity: number) => number
    
  4. ReturnType<typeof calculateTotal> examines that function type.

  5. It extracts the output portion after =>.

  6. Therefore, Total is number.

ReturnType affects only TypeScript's compile-time type checking. It does not call the function or change JavaScript generated at runtime.

Real World Use Cases

Common uses include:

  • Factory functions: Derive the type of an object created by a function.

    function createConfig() {
      return { retries: 3, logging: true };
    }
    
    type Config = ReturnType<typeof createConfig>;
    
  • API client helpers: Reuse the result type from a request function.

    async function fetchProducts() {
      return [{ id: 1, name: "Keyboard" }];
    }
    
    type Products = Awaited<ReturnType<typeof fetchProducts>>;
    
  • State initialization: Ensure state matches the value produced by a setup function.

    function initialFilters() {
      return { query: "", page: 1 };
    }
    
    type Filters = ReturnType<typeof initialFilters>;
    
  • Library wrappers: Keep wrapper code synchronized when an underlying function's result changes.

Take Quiz

Real Codebase Usage

In production code, ReturnType is most useful when it eliminates duplicated type declarations.

Derive a factory result

function createSession(userId: string) {
  return {
    userId,
    createdAt: new Date(),
    token: crypto.randomUUID(),
  };
}

type Session = ReturnType<typeof createSession>;

function saveSession(session: Session): void {
  // Save the session.
}

If createSession later adds a property, Session updates automatically.

Combine it with Awaited for async code

An async function returns a Promise, so ReturnType includes that promise:

async function getAccount(id: string) {
  return { id, plan: "pro" as const };
}

type AccountPromise = ReturnType<typeof getAccount>;
// Promise<{ id: string; plan: "pro" }>

type Account = Awaited<ReturnType<typeof getAccount>>;
// { id: string; plan: "pro" }

Use it for callbacks

const toDisplayName = (first: string, last: string) => `${first} ${last}`;

type DisplayName = ReturnType<typeof toDisplayName>;
// string

Prefer explicit exported interfaces or type aliases when they make a public API easier to understand. Use ReturnType when the type should intentionally follow a function implementation.

Common Mistakes

Using typeof alone

This gives the function type, not its output type:

function test(): number {
  return 42;
}

type T = typeof test; // () => number

Fix it by wrapping the function type in ReturnType:

type T = ReturnType<typeof test>; // number

Calling the function in a type position

This is not valid TypeScript type syntax:

// type T = typeof test(); // Invalid

Use ReturnType<typeof test> instead. Types describe code without executing it.

Forgetting that async functions return promises

async function loadCount(): Promise<number> {
  return 5;
}

type T = ReturnType<typeof loadCount>; // Promise<number>

If you need the resolved value, unwrap it:

type Count = Awaited<ReturnType<typeof loadCount>>; // number

Passing a non-function type

ReturnType only accepts function types.

type Broken = ReturnType<string>; // Error: string is not a function type

Expecting ReturnType to preserve every overload result

For an overloaded function, TypeScript generally infers from the last overload signature. If each overload's result must be represented precisely, define and use a more specific function type instead.

Comparisons

Tool or syntaxWhat it describesExample result
typeof testThe function value's complete type() => number
ReturnType<typeof test>The function's output typenumber
Parameters<typeof test>A tuple of input parameter types[]
Awaited<ReturnType<typeof asyncFn>>The resolved output of an async functionnumber instead of Promise<number>
Explicit return annotationDocuments or constrains a function's outputfunction test(): number

ReturnType is best when a function already exists and another type should follow its result. An explicit return annotation is best when you want to state the function's intended contract directly.

Take Quiz

Cheat Sheet

function test(): number {
  return 42;
}

// Full function signature
type FunctionType = typeof test;
// () => number

// Return value type
type Result = ReturnType<typeof test>;
// number
// Function type written directly
type Result = ReturnType<(id: string) => boolean>;
// boolean
// Async function: promise type
type PromiseResult = ReturnType<typeof fetchData>;
// Promise<Data>

// Async function: resolved type
type Data = Awaited<ReturnType<typeof fetchData>>;

Rules:

  • Pass a function type to ReturnType.
  • Use typeof functionName to obtain a named function's type.
  • ReturnType is compile-time only; it does not execute code.
  • Use Parameters<typeof fn> to extract inputs instead of outputs.

FAQ

How do I get a function's return type in TypeScript?

Use ReturnType with the function's type:

type Result = ReturnType<typeof test>;

Why does typeof test return () => number instead of number?

test refers to the function itself, not the value returned after calling it. Therefore, typeof test describes its callable signature.

Does ReturnType call the function?

No. It is a TypeScript utility type used only during type checking. It has no runtime behavior.

How do I get the return type of an async function?

ReturnType<typeof fn> gives the promise type. Use Awaited to get the resolved value type:

type Value = Awaited<ReturnType<typeof fn>>;

Can I use ReturnType with arrow functions?

Yes.

const isReady = () => true;
type Ready = ReturnType<typeof isReady>; // boolean

Can I get a function's parameter types too?

Yes. Use the built-in Parameters<T> utility type:

type Args = Parameters<typeof test>; // []

What happens with overloaded functions?

ReturnType usually uses the last overload signature. For precise behavior, create a specific function type for the overload case you need.

Take Quiz

Mini Project

Description

Build a small order-summary module. A factory function creates an order summary object, and other functions reuse its derived return type. This demonstrates how ReturnType keeps related code synchronized as the factory changes.

Goal

Create and use a ReturnType<typeof createOrderSummary> alias instead of manually repeating the order summary object type.

Requirements

Create a createOrderSummary function that accepts an item name, unit price, and quantity. Return an object containing the item name, quantity, subtotal, tax, and total. Create an OrderSummary type using ReturnType<typeof createOrderSummary>. Write a printReceipt function that accepts an OrderSummary. Create one summary and print its receipt.

Take Quiz

Keep learning

Related questions

View more