How to fix Generator function must return Generator type in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 10, 2025· 161 views

This TypeScript error occurs when a generator function is incorrectly typed, either returning a non-Generator type or having incompatible type parameters. Generator functions in TypeScript must return a Generator<T, TReturn, TNext> type, which represents both an iterator and iterable object.

Quick fix

Fixes TS2318

// WRONG - using Iterable or Iterator
function* countToThree(): Iterable<number> {
  yield 1;
  yield 2;
  yield 3;
}

// CORRECT - using Generator
function* countToThree(): Generator<number> {
  yield 1;
  yield 2;
  yield 3;
}

// With all three type parameters
function* createCounter(): Generator<number, void, number> {
  let count = 0;
  while (true) {
    const reset = yield count++;
    if (reset === 0) {
      count = 0;
    }
  }
}
  1. Use the correct Generator type annotation
  2. Let TypeScript infer the return type when possible
  3. Fix async generator functions with AsyncGenerator type
  4. Handle complex yield/return patterns correctly
typescript — error
// WRONG - using Iterable or Iterator
function* countToThree(): Iterable<number> {
yield 1;
yield 2;
yield 3;
}
// CORRECT - using Generator
function* countToThree(): Generator<number> {
yield 1;
yield 2;
yield 3;
}
// With all three type parameters
function* createCounter(): Generator<number, void, number> {
let count = 0;
while (true) {
const reset = yield count++;
if (reset === 0) {
count = 0;
}
}
}
Generator function must return Generator type

What this error means

The "Generator function must return Generator type" error appears when TypeScript detects that a function declared with the `function*` syntax (a generator function) has an incorrect return type annotation. Generator functions are special functions that can be paused and resumed using the `yield` keyword, and they always return a Generator object. In TypeScript, generator functions must be typed to return a `Generator<T, TReturn, TNext>` type, where: - `T` is the type of values yielded by the generator - `TReturn` is the type of value returned when the generator completes (defaults to `any`) - `TNext` is the type of value that can be passed to `next()` (defaults to `unknown`) This error typically occurs when: 1. You explicitly annotate a generator function with the wrong return type 2. Type inference fails due to complex yield/return patterns 3. You're using older TypeScript versions with different generator type rules 4. The generator function signature doesn't match the actual implementation

Typical symptoms

  • Compilation fails with 'Generator function must return Generator type'
  • IDE shows red underlines on generator function declarations
  • Error appears when explicitly typing a generator function's return
  • Code works in JavaScript but fails TypeScript compilation
  • Generator functions with complex yield/return patterns show type errors
  • Async generator functions may show similar errors with AsyncGenerator type

Common causes

  1. Explicitly annotating a generator function with a non-Generator return type
  2. Using Iterable<T> or Iterator<T> instead of Generator<T> as return type
  3. Mismatch between yield type and Generator type parameter
  4. Incorrect type parameters in Generator<T, TReturn, TNext> annotation
  5. Using older TypeScript versions with stricter generator type checking
  6. Async generator functions incorrectly typed as Generator instead of AsyncGenerator
  7. Type inference failure due to conditional yields or complex control flow
  8. Missing or incorrect lib.d.ts declarations for generator types

How to fix "Generator function must return Generator type"

1Use the correct Generator type annotation

Generator functions must return a Generator<T, TReturn, TNext> type. The simplest form is Generator<T>:

typescript
// WRONG - using Iterable or Iterator
function* countToThree(): Iterable<number> {
  yield 1;
  yield 2;
  yield 3;
}

// CORRECT - using Generator
function* countToThree(): Generator<number> {
  yield 1;
  yield 2;
  yield 3;
}

// With all three type parameters
function* createCounter(): Generator<number, void, number> {
  let count = 0;
  while (true) {
    const reset = yield count++;
    if (reset === 0) {
      count = 0;
    }
  }
}

The three type parameters are:
1. T - Type of yielded values (number in the example)
2. TReturn - Type returned when generator completes (void if no return statement)
3. TNext - Type passed to next() method (number for reset value)

2Let TypeScript infer the return type when possible

TypeScript can usually infer generator return types correctly. Omit explicit annotations unless necessary:

typescript
// Let TypeScript infer - usually works fine
function* generateIds() {
  let id = 0;
  while (true) {
    yield id++;
  }
}

// TypeScript infers: Generator<number, never, unknown>

// Only annotate when inference fails or for documentation
function* parseLines(text: string): Generator<string> {
  for (const line of text.split('
')) {
    yield line.trim();
  }
}

Check the inferred type by hovering over the function name in your IDE. If TypeScript infers correctly, you don't need explicit annotations.

3Fix async generator functions with AsyncGenerator type

Async generator functions (using async function*) must return AsyncGenerator<T, TReturn, TNext>:

typescript
// WRONG - using Generator for async function
async function* fetchPages(): Generator<Promise<string>> {
  for (let i = 0; i < 5; i++) {
    const response = await fetch(`/api/page/${i}`);
    yield response.text();
  }
}

// CORRECT - using AsyncGenerator
async function* fetchPages(): AsyncGenerator<string> {
  for (let i = 0; i < 5; i++) {
    const response = await fetch(`/api/page/${i}`);
    yield response.text();
  }
}

// With explicit return type
async function* timer(seconds: number): AsyncGenerator<string, void, unknown> {
  for (let i = 0; i < seconds; i++) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield `Tick ${i + 1}`;
  }
}

Async generators yield Promises or values, and the AsyncGenerator type handles the asynchronous nature.

4Handle complex yield/return patterns correctly

Generators with multiple yield types or conditional returns need proper type annotations:

typescript
// WRONG - mixed yields without proper union type
function* mixedGenerator(flag: boolean) {
  if (flag) {
    yield "string";
  } else {
    yield 42;
  }
  return true;
}

// CORRECT - explicit union type for yields
function* mixedGenerator(flag: boolean): Generator<string | number, boolean> {
  if (flag) {
    yield "string";
  } else {
    yield 42;
  }
  return true;
}

// Complex example with different next() input types
function* interactive(): Generator<string, void, string | number> {
  let input: string | number;
  while ((input = yield "Enter something:") !== "quit") {
    console.log(`You entered: ${input}`);
  }
}

For generators that never return (infinite loops), use never as the return type:

typescript
function* infiniteNumbers(): Generator<number, never> {
  let n = 0;
  while (true) {
    yield n++;
  }
}
5Update TypeScript configuration if needed

Ensure your tsconfig.json supports generator syntax and has appropriate lib files:

json
{
  "compilerOptions": {
    "target": "es2015",  // or higher for generator support
    "lib": ["es2015", "dom"],  // includes generator types
    "downlevelIteration": true  // if targeting ES5
  }
}

For older TypeScript versions, you might need:
- "target": "es6" or higher for native generator support
- "downlevelIteration": true if targeting ES5 with polyfills
- Appropriate lib files (es2015 or es2015.generator)

Check your TypeScript version:

bash
npx tsc --version

Consider updating if you're below TypeScript 2.3, which improved generator type inference.

6Use utility types for complex generator patterns

For reusable generator patterns, create utility types:

typescript
// Type for a generator that yields T and returns R
type SimpleGenerator<T, R = void> = Generator<T, R>;

// Type for an infinite generator
type InfiniteGenerator<T> = Generator<T, never>;

// Factory function with proper typing
function createCounter(start = 0): Generator<number> {
  return (function* () {
    let n = start;
    while (true) {
      yield n++;
    }
  })();
}

// Generic generator wrapper
function* mapGenerator<T, U>(
  generator: Generator<T>,
  mapper: (value: T) => U
): Generator<U> {
  for (const value of generator) {
    yield mapper(value);
  }
}

// Usage
const numbers = createCounter();
const doubled = mapGenerator(numbers, n => n * 2);

These patterns help maintain type safety across generator compositions.

Advanced notes

### Generator Type Parameters Deep Dive

The Generator<T, TReturn, TNext> interface has three type parameters:

1. `T` (Yield type): Type of values yielded with yield expression
- Can be a union type for multiple yield types
- Use unknown or any for dynamic yields (not recommended)

2. `TReturn` (Return type): Type returned when generator completes
- Defaults to any if omitted
- Use void if generator has no return statement
- Use never for infinite generators

3. `TNext` (Next type): Type of value passed to next(value)
- Defaults to unknown if omitted
- Usually matches T for simple generators
- Can differ for bidirectional communication

### Generator vs Iterable vs Iterator

Understanding the differences:

- Iterator<T>: Object with next(): IteratorResult<T> method
- Iterable<T>: Object with [Symbol.iterator](): Iterator<T> method
- Generator<T, TReturn, TNext>: Both Iterator<T> and Iterable<T>, plus return() and throw() methods

All generators are iterables, but not all iterables are generators.

### TypeScript Version Differences

Generator type checking has evolved:

- TypeScript 2.3+: Improved inference for generator return types
- TypeScript 3.6+: Better support for generator type parameters
- TypeScript 4.0+: Variadic tuple types can affect generator inference

If you encounter this error in older codebases, consider updating TypeScript or adding explicit type annotations.

### AsyncGenerator and Observables

For reactive programming patterns, consider these alternatives:

typescript
// Async generators for streams
async function* webSocketStream(url: string): AsyncGenerator<MessageEvent> {
  const ws = new WebSocket(url);
  try {
    while (ws.readyState !== WebSocket.CLOSED) {
      yield await new Promise(resolve => {
        ws.onmessage = resolve;
      });
    }
  } finally {
    ws.close();
  }
}

// RxJS Observables (alternative pattern)
import { Observable } from 'rxjs';

function intervalObservable(ms: number): Observable<number> {
  return new Observable(subscriber => {
    let count = 0;
    const id = setInterval(() => {
      subscriber.next(count++);
    }, ms);
    return () => clearInterval(id);
  });
}

### Debugging Generator Type Errors

Use these techniques to debug complex generator type issues:

1. Check inferred types: Hover over generator function in IDE
2. Use type assertions temporarily: function* g() { ... } as any
3. Simplify complex generators: Break into smaller, typed functions
4. Test with concrete types: Replace generics with concrete types temporarily

### Performance Considerations

Generator objects have overhead:
- Each generator maintains its execution state
- TypeScript's generator downleveling for ES5 adds polyfill code
- For performance-critical code, consider alternatives like arrays or custom iterators

However, generators excel at:
- Lazy evaluation of large/infinite sequences
- Complex control flow with pause/resume
- Async data streams with backpressure

Frequently asked questions

What does "TS2318" mean?
The "Generator function must return Generator type" error appears when TypeScript detects that a function declared with the function* syntax (a generator function) has an incorrect return type annotation. Generator functions are special functions that can be paused and resumed using the yield keyword, and they always return a Generator object. In TypeScript, generator functions must be typed to return a Generator<T, TReturn, TNext> type, where: - T is the type of values yielded by the generator - TReturn is the type of value returned when the generator completes (defaults to any) - TNext is the type of value that can be passed to next() (defaults to unknown) This error typically occurs when: 1.
How do I fix "TS2318"?
This TypeScript error occurs when a generator function is incorrectly typed, either returning a non-Generator type or having incompatible type parameters. Generator functions in TypeScript must return a Generator<T, TReturn, TNext> type, which represents both an iterator and iterable object.
What causes "TS2318"?
Explicitly annotating a generator function with a non-Generator return type Using Iterable<T> or Iterator<T> instead of Generator<T> as return type Mismatch between yield type and Generator type parameter
Is the "TS2318" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading