How to Specify the Return Type for a TypeScript Arrow Function

Place a colon and the type annotation immediately after the parameter list and before the fat arrow, like (param: string): number => param.length.

When working with the microsoft/TypeScript compiler, you can specify the return type for a TypeScript arrow function by adding an explicit type annotation between the closing parenthesis of the parameters and the => token. This annotation is stored in the type property of the ArrowFunction AST node and used by the type checker to validate return statements.

Syntax for Explicit Return Type Annotations

To specify a return type, place a colon followed by the type immediately after the closing parenthesis of the parameter list:

const functionName = (param: Type): ReturnType => expression;

This syntax applies to all arrow function variations, including those with single parameters, multiple parameters, and no parameters.

Here are practical examples demonstrating different return type annotations:

// Simple number return type
const square = (n: number): number => n * n;

// String return type with multiple parameters
const concat = (a: string, b: string): string => a + b;

// Object return type using a type alias
type Point = { x: number; y: number };
const makePoint = (x: number, y: number): Point => ({ x, y });

// Void return type for functions that don't return a value
const log = (msg: string): void => {
    console.log(msg);
};

// Generic arrow function with constrained return type
const identity = <T>(value: T): T => value;

// Async arrow function with Promise return type
const fetchJson = async (url: string): Promise<any> => {
    const response = await fetch(url);
    return response.json();
};

How the TypeScript Compiler Processes Return Types

The TypeScript compiler stores explicit return type annotations in the Abstract Syntax Tree (AST) and uses them during type checking and emit phases.

AST Representation and the ArrowFunction Interface

According to the microsoft/TypeScript source code, the ArrowFunction interface in src/lib/typescript.d.ts (around line 4998) declares a type property that holds the return type annotation:

interface ArrowFunction extends SignatureDeclaration, JSDocContainer {
    readonly kind: SyntaxKind.ArrowFunction;
    readonly equalsGreaterThanToken: EqualsGreaterThanToken;
    readonly body: ConciseBody;
    readonly type?: TypeNode;  // The explicit return type annotation
}

When you specify a return type, the parser creates a TypeNode representing that type and assigns it to the type property. If you omit the annotation, this property remains undefined, and the type checker infers the return type from the function body.

Factory Function and Node Creation

The compiler uses the createArrowFunction factory method in src/compiler/factory/nodeFactory.ts (around line 3246) to construct arrow function nodes. This factory accepts an optional type parameter that becomes the return type annotation on the resulting AST node:

// Simplified representation of the factory signature
function createArrowFunction(
    modifiers: readonly Modifier[] | undefined,
    typeParameters: readonly TypeParameterDeclaration[] | undefined,
    parameters: readonly ParameterDeclaration[],
    type: TypeNode | undefined,  // The explicit return type
    equalsGreaterThanToken: EqualsGreaterThanToken,
    body: ConciseBody
): ArrowFunction;

When the parser encounters a return type annotation in your source code, it passes the parsed TypeNode to this factory, ensuring the explicit type is preserved in the AST for subsequent compiler phases.

Why Explicit Return Types Matter

Explicit return type annotations serve critical functions across type checking, editor tooling, and declaration file generation.

Type Checking and Validation

The TypeScript type checker uses the explicit return type to validate that all return statements within the function body are assignable to the declared type. When checking an arrow function, the compiler reads the type property from the ArrowFunction node (if present) and uses it as the expected return type for the function signature.

If you annotate a return type as number but return a string, the checker reports an error because the actual return type is not assignable to the annotated NumberKeyword type node stored in the AST.

Editor Tooling and Refactorings

Editor features such as quick info, signature help, and refactorings rely on the type property of ArrowFunction nodes. For example, the "Infer function return type" refactoring in src/services/refactors/inferFunctionReturnType.ts (around line 15) examines existing return type annotations to determine whether to suggest adding an explicit type or modifying an existing one.

When you hover over an arrow function in an IDE, the language service reads the type property from the AST to display the explicit return type in the tooltip, or infers it from the body if the property is undefined.

Declaration File Generation

When TypeScript generates .d.ts declaration files, it includes explicit return type annotations in the emitted function signatures. If you omit the return type, the compiler must infer it and may emit a broader or more complex type than intended. Explicit annotations ensure that the public API surface documented in declaration files matches your intended contract precisely.

For example, an arrow function without an explicit return type might infer a complex union type that exposes internal implementation details, whereas an explicit annotation restricts the emitted declaration to the intended public type.

Common Patterns and Examples

Beyond basic primitives, you often need to specify return types for complex scenarios including async functions, generics, and functions returning objects or void.

Async Arrow Functions

For async arrow functions, the return type is typically Promise<T> where T represents the resolved value type:

const fetchUser = async (id: number): Promise<{ name: string; id: number }> => {
    const response = await fetch(`/api/users/${id}`);
    return response.json();
};

// Void async function
const delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));

Generic Arrow Functions

When working with generics, you can constrain the return type to the type parameter:

// Returns the same type as the input
const identity = <T>(value: T): T => value;

// Constrained generic with specific return type
const extractKey = <T extends Record<string, any>, K extends keyof T>(
    obj: T,
    key: K
): T[K] => obj[key];

Object and Array Return Types

Use type aliases or interfaces to specify complex return types:

interface User {
    id: number;
    name: string;
    email: string;
}

const createUser = (name: string, email: string): User => ({
    id: Math.random(),
    name,
    email
});

// Array return type
const range = (start: number, end: number): number[] => 
    Array.from({ length: end - start }, (_, i) => start + i);

Summary

To specify the return type for a TypeScript arrow function, place a colon and the type annotation between the parameter list and the fat arrow (=>). The microsoft/TypeScript compiler stores this annotation in the type property of the ArrowFunction AST node defined in src/lib/typescript.d.ts, using the createArrowFunction factory in src/compiler/factory/nodeFactory.ts to construct the node.

  • Syntax: (parameters): ReturnType => expression or (parameters): ReturnType => { statements }
  • AST Storage: The explicit type becomes the type property on the ArrowFunction interface; if omitted, the property is undefined and the checker infers from the body
  • Type Safety: The checker validates that all return statements are assignable to the annotated type
  • Tooling: Editor features like quick info and the "Infer function return type" refactoring in src/services/refactors/inferFunctionReturnType.ts rely on this annotation
  • Declarations: Explicit types ensure precise .d.ts emit for public APIs

Frequently Asked Questions

Do I need to specify return types for arrow functions?

No, TypeScript can infer return types from the function body in most cases. However, explicit annotations improve code clarity, prevent accidental type widening, and ensure stable .d.ts declaration output. They are especially valuable for public API surfaces and complex generic functions where inference might produce unexpected union types.

What happens if I omit the return type annotation?

When you omit the return type, the type property on the ArrowFunction AST node remains undefined. During type checking, the compiler analyzes the function body and infers the return type by examining all return statements. This inferred type is then used for assignment checking and editor tooling, though it may be broader or more complex than an explicit annotation would specify.

Can I specify return types for async arrow functions?

Yes, async arrow functions use the same annotation syntax, but the return type must be a Promise<T> where T represents the resolved value type. For example: const fetchData = async (): Promise<User[]> => { ... }. The compiler stores this Promise type in the type property of the ArrowFunction node and unwraps it during type checking to validate the value returned from the async function body.

How do I specify a return type for a generic arrow function?

Generic arrow functions support return type annotations that reference the type parameters. Place the return type annotation after the parameter list but before the => token, such as const identity = <T>(value: T): T => value. The annotation can use the generic type parameter T or constrained variants like T extends SomeType. The compiler stores this generic type reference in the type property of the AST node and validates it against actual return values during type checking.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →