How to fix Type narrowing from typeof check produces 'never' in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025ยท 90 views

This error occurs when TypeScript's type narrowing eliminates all possible types from a union, leaving the impossible "never" type. It typically happens with typeof checks that exclude all valid type options.

Quick fix

Fixes Type narrowing from typeof check produces 'never'

function process(value: string | number) {
  if (typeof value === 'string') {
    // value is string here
  } else if (typeof value === 'number') {
    // value is number here
  } else {
    // value is never here - all cases handled
    console.log(value); // Error: value is never
  }
}
  1. Identify where the never type appears
  2. Check if the never type is intentional (exhaustive checking)
  3. Verify your union type definition
  4. Avoid negated typeof checks that exclude everything
typescript โ€” error
function process(value: string | number) {
if (typeof value === 'string') {
// value is string here
} else if (typeof value === 'number') {
// value is number here
} else {
// value is never here - all cases handled
console.log(value); // Error: value is never
}
}
Type narrowing from typeof check produces 'never'

What this error means

This error appears when TypeScript's control flow analysis determines that a variable can never have a valid type at a specific point in your code. This happens most commonly when using `typeof` type guards that eliminate every possible type from a union type. TypeScript uses the `never` type to represent values that can never occur. When you apply type guards (like `typeof x === "string"`) to narrow down union types, and all possible types have been eliminated through your checks, TypeScript assigns the `never` type to indicate an unreachable code path. The issue often arises from overly restrictive type guards, incorrect assumptions about what types a variable can hold, or bugs in TypeScript's type narrowing algorithm itself (particularly with complex object property narrowing or negated typeof checks).

Typical symptoms

  • Variable is typed as "never" after typeof checks in if/else blocks
  • TypeScript shows "Type 'never' is not assignable to type X" errors
  • Cannot access properties or methods on a variable narrowed to never
  • IDE shows unreachable code warnings in branches that should be valid
  • Type guard eliminates all possible types from a union unexpectedly

Common causes

  1. Using typeof checks that exclude all possible types from a union (e.g., checking for "string" and "number" on a string | number type)
  2. Negated typeof guards (typeof x !== "object") that incorrectly narrow to never
  3. Complex nested type guards that eliminate all type possibilities
  4. TypeScript compiler bug with property narrowing in certain edge cases
  5. Incorrect type annotations creating impossible type combinations
  6. Exhaustive type checking in switch/if statements where all cases have been handled

How to fix "Type narrowing from typeof check produces 'never'"

1Identify where the never type appears

First, locate exactly where TypeScript is inferring the never type. Hover over the variable in your IDE or check the compiler error message:

typescript
function process(value: string | number) {
  if (typeof value === 'string') {
    // value is string here
  } else if (typeof value === 'number') {
    // value is number here
  } else {
    // value is never here - all cases handled
    console.log(value); // Error: value is never
  }
}

The never type indicates that this code path should be unreachable given the type constraints.

2Check if the never type is intentional (exhaustive checking)

Sometimes never is actually desired for exhaustive type checking. This is a common pattern to ensure all union cases are handled:

typescript
type Action = { type: 'add' } | { type: 'remove' };

function handleAction(action: Action) {
  switch (action.type) {
    case 'add':
      return 'Adding';
    case 'remove':
      return 'Removing';
    default:
      // This should be never - proves exhaustiveness
      const _exhaustive: never = action;
      throw new Error(`Unhandled action: ${_exhaustive}`);
  }
}

If this is your use case, the never type is working correctly.

3Verify your union type definition

Check that your type annotation actually includes all the types you expect. A mismatch here causes unexpected narrowing:

typescript
// Problem: type doesn't include all expected values
let value: string | number = getValue();

if (typeof value === 'boolean') {
  // value is never - boolean not in union
  console.log(value);
}

// Solution: Include all possible types
let value: string | number | boolean = getValue();

if (typeof value === 'boolean') {
  // value is boolean - works correctly
  console.log(value);
}
4Avoid negated typeof checks that exclude everything

Negated typeof checks can be problematic. Instead of checking what something is NOT, check what it IS:

typescript
// Problem: negated check narrows incorrectly
function process(value: string | number | object) {
  if (typeof value !== 'object') {
    // May narrow to never in some TS versions
  }
}

// Solution: Use positive type guards
function process(value: string | number | object) {
  if (typeof value === 'string' || typeof value === 'number') {
    // value is string | number
    console.log(value);
  } else {
    // value is object
    console.log(value);
  }
}
5Use type predicates for complex narrowing

For complex type checking, custom type predicates give you more control than typeof:

typescript
interface Cat { meow(): void }
interface Dog { bark(): void }

type Animal = Cat | Dog;

// Type predicate function
function isCat(animal: Animal): animal is Cat {
  return 'meow' in animal;
}

function handleAnimal(animal: Animal) {
  if (isCat(animal)) {
    animal.meow(); // Correctly narrowed to Cat
  } else {
    animal.bark(); // Correctly narrowed to Dog
  }
}
6Add an escape hatch for unexpected never types

If you encounter a never type that shouldn't exist (possibly a TypeScript bug), you can work around it temporarily:

typescript
// Workaround: Type assertion
function process(value: string | number) {
  if (typeof value === 'string') {
    // handle string
  } else {
    // TypeScript thinks this is never incorrectly
    const numValue = value as number;
    console.log(numValue);
  }
}

// Better: Widen the type explicitly
function process(value: string | number) {
  const widened: string | number = value;
  if (typeof widened === 'string') {
    // handle string
  } else {
    console.log(widened); // number, not never
  }
}

Advanced notes

Understanding never in the type system:

The never type is the bottom type in TypeScript's type hierarchy. It's assignable to every type, but no type is assignable to never (except never itself). This makes it perfect for representing impossible states and unreachable code.

Known TypeScript issues:

Several GitHub issues document cases where typeof narrowing produces unexpected never types:

- Issue #27103: typeof narrowing with object types can incorrectly produce never
- Issue #32585: Property narrowing in loops can produce weird never types
- Issue #41270: Union types in let declarations can be erroneously narrowed to never
- Issue #54032: Creating never from void functions using typeof

These are typically edge cases involving complex type combinations, property access in narrowed types, or interactions between control flow analysis and type guards.

Discriminated unions vs typeof:

For complex object types, discriminated unions are more reliable than typeof checks:

typescript
// Instead of typeof checks
type Response =
  | { success: true; data: string }
  | { success: false; error: string };

function handle(response: Response) {
  if (response.success) {
    console.log(response.data); // Correctly narrowed
  } else {
    console.log(response.error); // Correctly narrowed
  }
}

StrictNullChecks impact:

With strictNullChecks enabled, the never type appears more frequently because TypeScript is more aggressive about eliminating impossible type combinations. This is generally desirable as it catches more bugs at compile time.

Frequently asked questions

What does "Type narrowing from typeof check produces 'never'" mean?
This error appears when TypeScript's control flow analysis determines that a variable can never have a valid type at a specific point in your code. This happens most commonly when using typeof type guards that eliminate every possible type from a union type. TypeScript uses the never type to represent values that can never occur.
How do I fix "Type narrowing from typeof check produces 'never'"?
This error occurs when TypeScript's type narrowing eliminates all possible types from a union, leaving the impossible "never" type. It typically happens with typeof checks that exclude all valid type options.
What causes "Type narrowing from typeof check produces 'never'"?
Using typeof checks that exclude all possible types from a union (e.g., checking for "string" and "number" on a string | number type) Negated typeof guards (typeof x !== "object") that incorrectly narrow to never Complex nested type guards that eliminate all type possibilities
Is the "Type narrowing from typeof check produces 'never'" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading