How to fix Property 'name' does not exist on type 'never' in TypeScript
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'
}- Identify the union type and narrowing logic
- Handle all union cases explicitly
- Use exhaustiveness checking with assertNever
- Fix incomplete type guards
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 handledreturn 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
- Missing cases in switch statements (most common)
- Incomplete if/else chains for union types
- Type guards that don't cover all possible types
- Using exhaustive checking pattern incorrectly
- Discriminated union without handling all discriminants
- Type narrowing that eliminates all possibilities prematurely
- Using 'never' as a return type incorrectly
How to fix "Property 'name' does not exist on type 'never'"
First, find where the 'never' type originates. Look for union types and conditional checks:
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.
Ensure every possible type in the union is accounted for:
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:
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
}
}Create a helper function to catch unhandled cases at compile time:
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.
Ensure type predicates cover all possibilities:
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.
Avoid forcing types that TypeScript knows are impossible:
// ❌ 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.
Enable strict mode to catch these errors early:
{
"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':
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'):
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:
// 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:
// 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
- 📚TypeScript Official Documentation
- 📖
- 📖TypeScript Handbook: Unions and Intersection Types(Official Docs)
- 📖TypeScript Handbook: The never Type(Official Docs)
- 🐙