How to fix Cannot access property of type 'never' in non-null assertion in TypeScript

TypeScriptINTERMEDIATEMEDIUMUpdated Dec 11, 2025· 104 views

This TypeScript error occurs when you try to access properties on a value that TypeScript has determined is unreachable (type 'never'), often combined with non-null assertions (!). The fix involves proper type narrowing and avoiding unsafe assertions on impossible values.

Quick fix

Fixes Cannot access property of type 'never' in non-null assertion

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

function getMessage(status: Status): string {
  if (status === 'pending') {
    return 'Processing...';
  } else if (status === 'success') {
    return 'Done!';
  }
  // At this point, TypeScript knows status is 'never'
  // But if you try to use ! here, you'll get the error:
  return status!.toUpperCase(); // ERROR: Cannot access property of type never
}
  1. Identify where the non-null assertion meets 'never'
  2. Replace non-null assertions with proper type handling
  3. Use exhaustiveness checking instead of assertions
  4. Avoid non-null assertions in exhaustive branches
typescript — error
type Status = 'pending' | 'success' | 'error';
function getMessage(status: Status): string {
if (status === 'pending') {
return 'Processing...';
} else if (status === 'success') {
return 'Done!';
}
// At this point, TypeScript knows status is 'never'
// But if you try to use ! here, you'll get the error:
return status!.toUpperCase(); // ERROR: Cannot access property of type never
}
Cannot access property of type 'never' in non-null assertion

What this error means

The 'never' type in TypeScript represents values that should never occur—an impossible state. When you see this error with a non-null assertion (!), it means you're trying to force TypeScript to treat an impossible value as if it exists. This happens when: 1. TypeScript's control flow analysis determines a code path is unreachable 2. You use a non-null assertion (!) on a value that TypeScript knows is 'never' 3. You're trying to access properties on a value that logically cannot exist The non-null assertion operator (!) tells TypeScript "trust me, this value isn't null or undefined," but it doesn't work on 'never' because 'never' means "this value can never exist at all." TypeScript is warning you that your code logic has a contradiction: you're asserting something exists when the type system says it's impossible.

Typical symptoms

  • TypeScript compiler error mentioning 'never' type with non-null assertion
  • Error message: 'Cannot access property of type never in non-null assertion'
  • The error appears after using the ! operator on a narrowed value
  • Related to exhaustive type checking in switch statements or if/else chains
  • Occurs when trying to force property access on impossible values
  • Often appears with discriminated unions and exhaustive pattern matching

Common causes

  1. Using non-null assertion on exhaustively narrowed union types (most common)
  2. Missing cases in switch statements followed by property access with !
  3. Incomplete type guards that leave 'never' type in certain branches
  4. Trying to access properties after assertNever or exhaustive check functions
  5. Using ! on values that TypeScript knows are unreachable due to control flow
  6. Combining non-null assertions with type predicates that eliminate all possibilities
  7. Forgetting to handle all union cases before using non-null assertions

How to fix "Cannot access property of type 'never' in non-null assertion"

1Identify where the non-null assertion meets 'never'

First, locate the ! operator that's causing the error. Look for patterns like:

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

function getMessage(status: Status): string {
  if (status === 'pending') {
    return 'Processing...';
  } else if (status === 'success') {
    return 'Done!';
  }
  // At this point, TypeScript knows status is 'never'
  // But if you try to use ! here, you'll get the error:
  return status!.toUpperCase(); // ERROR: Cannot access property of type never
}

Use your IDE's hover feature to see what type TypeScript infers at the point of the ! operator.

2Replace non-null assertions with proper type handling

Instead of forcing TypeScript with !, handle the 'never' case properly:

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

function getMessage(status: Status): string {
  if (status === 'pending') {
    return 'Processing...';
  } else if (status === 'success') {
    return 'Done!';
  } else {
    // Handle the 'error' case explicitly
    return 'Error occurred';
  }
  // No need for ! operator
}

Or use a switch statement with all cases covered:

typescript
function getMessage(status: Status): string {
  switch (status) {
    case 'pending':
      return 'Processing...';
    case 'success':
      return 'Done!';
    case 'error':
      return 'Error occurred';
  }
}
3Use exhaustiveness checking instead of assertions

Create an exhaustiveness check function that catches unhandled cases at compile time:

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

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

function getMessage(status: Status): string {
  switch (status) {
    case 'pending':
      return 'Processing...';
    case 'success':
      return 'Done!';
    default:
      // TypeScript knows this is 'never' if all cases are handled
      assertNever(status);
  }
}

If you add a new value to the Status union and forget to handle it, TypeScript will error at the assertNever call, preventing runtime errors.

4Avoid non-null assertions in exhaustive branches

When TypeScript has narrowed a type to 'never', don't use !—instead, restructure your code:

typescript
// BAD: Using ! on never
function processValue(value: string | null) {
  if (value === null) {
    throw new Error('Value is null');
  }
  // value is string here
  return value.toUpperCase();
}

// GOOD: Proper null handling without !
function processValue(value: string | null): string {
  if (value === null) {
    throw new Error('Value is null');
  }
  return value.toUpperCase();
}

// BAD with unions:
type Result = { type: 'data'; data: string } | { type: 'error' };

function handleResult(result: Result) {
  if (result.type === 'data') {
    console.log(result.data);
  }
  // result is 'never' here (type 'error' not handled)
  // Don't use: console.log(result!.type);
}
5Use type predicates for safe property access

Define explicit type guards instead of using non-null assertions:

typescript
interface User { id: string; name: string }
interface Guest { sessionId: string }

type Visitor = User | Guest;

function isUser(visitor: Visitor): visitor is User {
  return 'id' in visitor && 'name' in visitor;
}

function getName(visitor: Visitor): string {
  if (isUser(visitor)) {
    return visitor.name; // Safe access, no ! needed
  } else {
    return 'Guest'; // Handle Guest case
  }
}

// Alternative: discriminated union
type Visitor2 =
  | { type: 'user'; id: string; name: string }
  | { type: 'guest'; sessionId: string };

function getName2(visitor: Visitor2): string {
  switch (visitor.type) {
    case 'user':
      return visitor.name; // Safe
    case 'guest':
      return 'Guest'; // Handled
  }
}
6Review TypeScript compiler options

Ensure your tsconfig.json has appropriate strictness settings:

json
{
  "compilerOptions": {
    "strict": true,
    "strictNullChecks": true,
    "noImplicitAny": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true
  }
}

These settings help catch type errors early, including unsafe non-null assertions on 'never' types.

Advanced notes

### Understanding the Intersection of 'never' and Non-Null Assertions

The non-null assertion operator (!) works by removing 'null' and 'undefined' from a type. However, 'never' is different—it's not about nullability, but about impossibility.

typescript
// What ! does:
type MaybeString = string | null | undefined;
type DefinitelyString = MaybeString!; // string

// What happens with never:
type Impossible = never;
type StillImpossible = Impossible!; // still never

### When Non-Null Assertions Are Appropriate

Use ! only when:
1. You know better than TypeScript (e.g., external data validation)
2. The value comes from outside TypeScript's type system
3. You've validated the value at runtime

Never use ! to override TypeScript's control flow analysis—it's telling you about a logical contradiction in your code.

### Pattern: Exhaustive Checking with Discriminated Unions

For complex scenarios, use discriminated unions with exhaustive checking:

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

function handleResponse<T>(response: ApiResponse<T>): string {
  switch (response.status) {
    case 'loading':
      return 'Loading...';
    case 'success':
      return `Data: ${response.data}`;
    case 'error':
      return `Error: ${response.message}`;
    default:
      // TypeScript ensures this is never reached
      const exhaustiveCheck: never = response;
      return exhaustiveCheck;
  }
}

### Edge Case: Async Functions and Promises

'never' can appear with promise types:

typescript
async function alwaysRejects(): Promise<never> {
  throw new Error('Always fails');
}

// Trying to use ! on the result is meaningless
async function badExample() {
  const result = await alwaysRejects();
  // result is 'never' - can't use result!
}

### Migration Strategy

If you're refactoring code with many ! operators:
1. First, enable strictNullChecks
2. Replace ! with proper null checks
3. Use optional chaining (?.) where appropriate
4. Add explicit type guards for complex cases
5. Use exhaustive checking for union types

### Performance Considerations

TypeScript's control flow analysis that produces 'never' types happens at compile time and has no runtime cost. Removing ! operators improves code safety without affecting performance.

Frequently asked questions

What does "Cannot access property of type 'never' in non-null assertion" mean?
The 'never' type in TypeScript represents values that should never occur—an impossible state. ), it means you're trying to force TypeScript to treat an impossible value as if it exists. This happens when: 1.
How do I fix "Cannot access property of type 'never' in non-null assertion"?
This TypeScript error occurs when you try to access properties on a value that TypeScript has determined is unreachable (type 'never'), often combined with non-null assertions (!). The fix involves proper type narrowing and avoiding unsafe assertions on impossible values.
What causes "Cannot access property of type 'never' in non-null assertion"?
Using non-null assertion on exhaustively narrowed union types (most common) Missing cases in switch statements followed by property access with ! Incomplete type guards that leave 'never' type in certain branches
Is the "Cannot access property of type 'never' in non-null assertion" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading