# How to Define a Type for forEach in TypeScript: Generic Implementation Patterns

> Learn to define a type for forEach in TypeScript. Explore generic implementation patterns to ensure type safety when iterating over collections. Improve your code quality now.

- Repository: [Microsoft/TypeScript](https://github.com/microsoft/typescript)
- Tags: how-to-guide
- Published: 2026-02-14

---

**Define a type for `forEach` in TypeScript by declaring generic parameters `T` for the element type and `U` for the callback return type, allowing the compiler to infer types from the collection being iterated.**

The `microsoft/TypeScript` repository demonstrates canonical patterns for typing `forEach`-style utilities using generic constraints. Whether you are building a compiler utility or a domain-specific collection library, understanding how to define a type for `forEach` in TypeScript ensures type safety across heterogeneous collections.

## The Core Generic Pattern in TypeScript

The TypeScript compiler implements a foundational `forEach` helper in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts) that serves as the reference implementation. This utility is generic over two type parameters: `T` represents the element type of the array, while `U` represents the return type of the callback function.

The signature at line 33 handles optional arrays and early termination:

```typescript
export function forEach<T, U>(
    array: readonly T[] | undefined,
    callback: (element: T, index: number) => U | undefined
): U | undefined;

```

This pattern allows the compiler to infer `T` from the array argument and `U` from the callback's return statement, maintaining strict type checking without explicit annotations at the call site.

## Implementing a Custom forEach Type

### Basic Array Implementation

To define a type for a custom `forEach` that processes every element without returning a value, use a single generic parameter for the element type:

```typescript
function forEach<T>(
  items: readonly T[],
  callback: (item: T, index: number) => void
): void {
  for (let i = 0; i < items.length; i++) {
    callback(items[i], i);
  }
}

```

### Handling Optional Collections

Following the pattern in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts), modify the signature to accept `undefined` for defensive programming:

```typescript
function forEach<T, U>(
  items: readonly T[] | undefined,
  callback: (item: T, index: number) => U | undefined
): U | undefined {
  if (!items) return undefined;
  
  for (let i = 0; i < items.length; i++) {
    const result = callback(items[i], i);
    if (result !== undefined) return result;
  }
  return undefined;
}

```

This implementation returns the first non-undefined value from the callback, enabling early-exit semantics similar to the TypeScript compiler's internal utilities.

## Advanced forEach Type Patterns

### Overloads for Complex Collections

The TypeScript repository includes React typings that demonstrate function overloads for `forEach` when handling polymorphic collections. In [`tests/lib/react18/react18.d.ts`](https://github.com/microsoft/TypeScript/blob/main/tests/lib/react18/react18.d.ts), the `Children.forEach` method uses overloads to handle both single children and arrays:

```typescript
// react18.d.ts lines 386 and 3035
forEach<C>(children: C | ReadonlyArray<C>, 
           fn: (child: C, index: number) => void): void;

```

This pattern preserves the specific child type `C` whether the input is a single element or a collection, preventing unnecessary widening to `unknown` or `any`.

### Record and Map Iteration

For dictionary-like structures, define generics for both keys and values:

```typescript
function forEach<K extends string, V, U>(
  record: Record<K, V> | undefined,
  callback: (value: V, key: K) => U | undefined
): U | undefined {
  if (!record) return undefined;
  
  for (const key in record) {
    if (Object.prototype.hasOwnProperty.call(record, key)) {
      const result = callback(record[key], key as K);
      if (result !== undefined) return result;
    }
  }
  return undefined;
}

```

## Using the Built-in Array.forEach Type

TypeScript's standard library defines the native `Array.prototype.forEach` in [`lib.es5.d.ts`](https://github.com/microsoft/TypeScript/blob/main/lib.es5.d.ts) with a simpler signature optimized for side effects:

```typescript
interface Array<T> {
  forEach(
    callbackfn: (value: T, index: number, array: T[]) => void,
    thisArg?: any
  ): void;
}

```

This built-in type automatically infers `T` from the array instance and enforces that the callback returns `void`, distinguishing it from transformation methods like `map` or `filter`.

## Summary

- **Use two generics** (`T` for elements, `U` for return values) when defining a type for `forEach` that may return early, as demonstrated in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts).
- **Accept `readonly T[] | undefined`** to make utilities defensive against nullish inputs without requiring call-site guards.
- **Leverage function overloads** for polymorphic collections where the same function must handle both single items and arrays, preserving specific type information.
- **Distinguish between side-effect and transformation semantics**: native `Array.forEach` returns `void`, while custom utilities may return `U | undefined` to enable early termination.

## Frequently Asked Questions

### What is the difference between typing `forEach` and `map` in TypeScript?

`forEach` is designed for side effects and typically returns `void` or `U | undefined` for early exit, while `map` always returns a new array of type `U[]` with the same length as the input. When defining types, `map` requires a return type parameter that becomes the array element type, whereas `forEach` either ignores the callback return or uses it for short-circuit logic.

### How do I type a `forEach` callback that modifies external state?

When a `forEach` callback modifies variables outside its scope, declare the state type explicitly and use a `void` return type for the callback to indicate side effects only. For example: `forEach(items: T[], callback: (item: T) => void)`. If the external state is complex, consider passing it as a parameter with a specific interface rather than relying on closure capture, which improves type safety and testability.

### Can I use `forEach` with async callbacks in TypeScript?

The standard `Array.prototype.forEach` does not handle async callbacks properly because it does not await promises and does not return a promise itself. To type an async-capable `forEach`, define the callback as returning `Promise<void>` or `Promise<U>` and wrap the iteration in an async function that awaits each callback. However, for async operations, `Promise.all` with `map` is generally preferred over `forEach` to ensure proper error handling and sequencing.

### Why does the TypeScript compiler use its own `forEach` helper instead of the native array method?

The TypeScript compiler defines its own `forEach` in [`src/compiler/core.ts`](https://github.com/microsoft/TypeScript/blob/main/src/compiler/core.ts) to support early termination (returning the first non-undefined value) and to safely handle `undefined` inputs without runtime errors. The native `Array.prototype.forEach` always iterates the entire array and returns `void`, which is inefficient for compiler operations that frequently search for specific nodes or symbols and need to exit early upon finding a match.