How to fix Property 'name' does not exist on type 'never' in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025· 106 views

This TypeScript error occurs when you try to access a property on a value that TypeScript has narrowed to type 'never'. It typically happens with incomplete type guards, missing union cases, or exhaustive switch statements. The fix involves proper type narrowing and exhaustiveness checking.

Quick fix

Fixes Property 'name' does not exist on type 'never'

type User = { type: 'admin'; name: string } | { type: 'guest' };

function getUserName(user: User): string {
  if (user.type === 'admin') {
    return user.name; // OK: user is narrowed to admin type
  }
  // ERROR: At this point, user is type 'never' if guest case isn't handled
  return user.name; // Property 'name' does not exist on type 'never'
}
  1. Identify the union type and narrowing logic
  2. Handle all union cases explicitly
  3. Use exhaustiveness checking with assertNever
  4. Fix incomplete type guards
typescript — error
type User = { type: 'admin'; name: string } | { type: 'guest' };
function getUserName(user: User): string {
if (user.type === 'admin') {
return user.name; // OK: user is narrowed to admin type
}
// ERROR: At this point, user is type 'never' if guest case isn't handled
return user.name; // Property 'name' does not exist on type 'never'
}
Property 'name' does not exist on type 'never'

What this error means

The 'never' type in TypeScript represents values that should never occur—an impossible or unreachable state. When you see "Property 'name' does not exist on type 'never'", TypeScript is telling you that: 1. **Type narrowing has eliminated all possible types**: Through conditional checks (if/else, switch), TypeScript has determined that a particular code path should be unreachable. 2. **You're accessing a property on an impossible value**: Since the type is 'never' (no possible values), you can't access properties like 'name' on it. 3. **There's a logical gap in your type handling**: This error usually indicates missing cases in union type handling or incomplete type guards. This is a compile-time safety feature, not a runtime error. TypeScript prevents you from writing code that assumes a value exists when its type system says it shouldn't.

Typical symptoms

  • TypeScript compiler error: 'Property 'X' does not exist on type 'never'
  • Error appears when accessing properties after conditional checks
  • Common with switch statements missing cases
  • Occurs in if/else chains that don't cover all union possibilities
  • Happens with discriminated unions when not all variants are handled
  • Error location is often after the last else or default case

Common causes

  1. Missing cases in switch statements (most common)
  2. Incomplete if/else chains for union types
  3. Type guards that don't cover all possible types
  4. Using exhaustive checking pattern incorrectly
  5. Discriminated union without handling all discriminants
  6. Type narrowing that eliminates all possibilities prematurely
  7. Using 'never' as a return type incorrectly

How to fix "Property 'name' does not exist on type 'never'"

1Identify the union type and narrowing logic

First, find where the 'never' type originates. Look for union types and conditional checks:

typescript
type User = { type: 'admin'; name: string } | { type: 'guest' };

function getUserName(user: User): string {
  if (user.type === 'admin') {
    return user.name; // OK: user is narrowed to admin type
  }
  // ERROR: At this point, user is type 'never' if guest case isn't handled
  return user.name; // Property 'name' does not exist on type 'never'
}

Use your IDE's hover feature to see the inferred type at each point in your code.

2Handle all union cases explicitly

Ensure every possible type in the union is accounted for:

typescript
type User = { type: 'admin'; name: string } | { type: 'guest' };

function getUserName(user: User): string {
  if (user.type === 'admin') {
    return user.name;
  } else {
    // Handle guest case explicitly
    return 'Guest User';
  }
}

Or with switch statements:

typescript
type Status = 'pending' | 'success' | 'error';

function getStatusMessage(status: Status): string {
  switch (status) {
    case 'pending':
      return 'Processing...';
    case 'success':
      return 'Completed successfully';
    case 'error':
      return 'An error occurred';
    // No default needed - all cases covered
  }
}
3Use exhaustiveness checking with assertNever

Create a helper function to catch unhandled cases at compile time:

typescript
function assertNever(value: never): never {
  throw new Error(`Unhandled value: ${JSON.stringify(value)}`);
}

type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'square'; side: number }
  | { kind: 'triangle'; base: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'square':
      return shape.side ** 2;
    case 'triangle':
      return 0.5 * shape.base * shape.height;
    default:
      // TypeScript ensures all cases are handled
      return assertNever(shape);
  }
}

If you add a new shape type to the union, TypeScript will error at assertNever until you handle it.

4Fix incomplete type guards

Ensure type predicates cover all possibilities:

typescript
interface Dog { type: 'dog'; name: string; bark(): void }
interface Cat { type: 'cat'; name: string; meow(): void }
interface Bird { type: 'bird'; name: string; chirp(): void }

type Animal = Dog | Cat | Bird;

function isMammal(animal: Animal): animal is Dog | Cat {
  return animal.type === 'dog' || animal.type === 'cat';
}

function handleAnimal(animal: Animal) {
  if (isMammal(animal)) {
    console.log(animal.name); // OK: Dog or Cat
    if (animal.type === 'dog') {
      animal.bark();
    } else {
      animal.meow();
    }
  } else {
    // animal is Bird
    console.log(animal.name); // OK: Bird
    animal.chirp();
  }
}

Make sure every branch of conditional logic handles a valid type.

5Check for impossible type assertions

Avoid forcing types that TypeScript knows are impossible:

typescript
// ❌ DON'T: Type assertion that creates 'never'
type Impossible = string & number; // Type is 'never'

function badExample(value: string | number) {
  if (typeof value === 'string') {
    // value is string
  } else if (typeof value === 'number') {
    // value is number
  } else {
    // value is never here
    const impossible = value as Impossible; // Creates problems
  }
}

// ✅ DO: Let TypeScript infer types naturally
function goodExample(value: string | number) {
  if (typeof value === 'string') {
    return value.toUpperCase();
  } else {
    return value.toFixed(2);
  }
}

Let TypeScript's type inference work naturally rather than forcing assertions.

6Use strict TypeScript configuration

Enable strict mode to catch these errors early:

json
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true
  }
}

Strict mode helps catch incomplete type handling before it causes runtime issues.

Advanced notes

### Understanding TypeScript's Control Flow Analysis

TypeScript uses control flow analysis to narrow types based on conditional checks. When all possibilities are exhausted, the remaining type is 'never':

typescript
type Direction = 'north' | 'south' | 'east' | 'west';

function getCoordinates(dir: Direction): [number, number] {
  switch (dir) {
    case 'north': return [0, 1];
    case 'south': return [0, -1];
    case 'east': return [1, 0];
    case 'west': return [-1, 0];
    default:
      // dir is 'never' here - all cases handled
      const exhaustiveCheck: never = dir;
      return exhaustiveCheck; // Compile-time safety
  }
}

### Discriminated Unions Best Practice

For complex type hierarchies, use a discriminant property (often called 'kind', 'type', or 'tag'):

typescript
type ApiResponse<T> =
  | { status: 'success'; data: T }
  | { status: 'error'; message: string }
  | { status: 'loading' };

function handleResponse<T>(response: ApiResponse<T>) {
  switch (response.status) {
    case 'success':
      return response.data;
    case 'error':
      throw new Error(response.message);
    case 'loading':
      return null;
    default:
      const _exhaustive: never = response;
      return _exhaustive;
  }
}

### The 'never' Type in Generic Constraints

'never' can appear in generic contexts:

typescript
// Function that should never be called
function unreachable(): never {
  throw new Error('This should never be called');
}

// Conditional type that results in 'never'
type Exclude<T, U> = T extends U ? never : T;

// Usage
type NonNullable<T> = T extends null | undefined ? never : T;
type Result = NonNullable<string | null>; // string

### Common Pitfalls

1. Empty arrays: [] has type never[] - an array that can't contain anything
2. Impossible intersections: string & number is never
3. Type guards with side effects: TypeScript can't track types through mutations
4. Function overloads: Incorrect overload signatures can create 'never' returns

### Testing Exhaustiveness

Add a test to ensure all union cases are handled:

typescript
// In your test suite
describe('exhaustiveness', () => {
  it('handles all Status cases', () => {
    const statuses: Status[] = ['pending', 'success', 'error'];
    statuses.forEach(status => {
      expect(() => getStatusMessage(status)).not.toThrow();
    });
  });
});

Frequently asked questions

What does "Property 'name' does not exist on type 'never'" mean?
The 'never' type in TypeScript represents values that should never occur—an impossible or unreachable state. When you see "Property 'name' does not exist on type 'never'", TypeScript is telling you that: 1. Type narrowing has eliminated all possible types: Through conditional checks (if/else, switch), TypeScript has determined that a particular code path should be unreachable.
How do I fix "Property 'name' does not exist on type 'never'"?
This TypeScript error occurs when you try to access a property on a value that TypeScript has narrowed to type 'never'. It typically happens with incomplete type guards, missing union cases, or exhaustive switch statements. The fix involves proper type narrowing and exhaustiveness checking.
What causes "Property 'name' does not exist on type 'never'"?
Missing cases in switch statements (most common) Incomplete if/else chains for union types Type guards that don't cover all possible types
Is the "Property 'name' does not exist on type '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