How to fix Type 'never' is not assignable to type 'string' in TypeScript
This error occurs when TypeScript infers a variable as the never type (representing impossible values) but you try to assign or use it where a string is expected, commonly from untyped empty arrays or over-narrowed type guards.
Quick fix
Fixes Type 'never' is not assignable to type 'string'
const items = [];
items.push("hello"); // Error: Argument of type 'string' is not assignable to parameter of type 'never'- Add explicit type annotation to empty arrays
- Review type narrowing logic for unreachable branches
- Provide explicit types for generic function parameters
- Use type assertions for impossible states you know are safe
const items = [];items.push("hello"); // Error: Argument of type 'string' is not assignable to parameter of type 'never'Type 'never' is not assignable to type 'string'
What this error means
The "Type 'never' is not assignable to type 'string'" error indicates that TypeScript has determined a value should be of type `never` (a type representing values that never occur) but you're trying to use it in a context expecting a `string`. The `never` type in TypeScript represents the type of values that never occur. When TypeScript infers `never`, it's typically because type narrowing through control flow analysis has eliminated all possible types, or because an empty array was declared without explicit typing, leading TypeScript to infer `never[]`. This means the array can never contain any elements according to TypeScript's analysis. This error commonly appears when working with arrays, conditional type narrowing, or union types where TypeScript's type inference becomes overly restrictive and narrows a type down to an impossible state. The compiler is essentially telling you that based on your code's logic, it believes no valid value can exist in this position, yet you're trying to treat it as a string.
Typical symptoms
- Empty array operations fail with type errors when trying to push string values
- Array indexing returns never type instead of expected element type
- Conditional type guards eliminate all possible types leaving never
- Type inference fails for array.reduce() or array.map() with empty arrays
- React useState hook infers never[] for empty array initial state
- Object property access returns never when all union branches are handled
Common causes
- Empty array declared without explicit type annotation, causing TypeScript to infer never[]
- Type narrowing through if/else or switch statements eliminates all possible union members
- Incorrect type guards that narrow a type to an impossible state
- Missing type annotation on useState or other generic hooks in React
- Array methods like reduce() with no initial value on an empty array
- Exhaustive type checking where all cases are handled but TypeScript expects a return value
- Using strictNullChecks mode with untyped empty arrays or objects
How to fix "Type 'never' is not assignable to type 'string'"
The most common cause is declaring an empty array without typing it. TypeScript infers never[] which cannot hold any elements.
Before (causes error):
const items = [];
items.push("hello"); // Error: Argument of type 'string' is not assignable to parameter of type 'never'After (fixed):
const items: string[] = [];
items.push("hello"); // OKFor React hooks:
const [items, setItems] = useState<string[]>([]);
setItems([...items, "hello"]); // OKIf type guards eliminate all possible types, TypeScript infers never. Check your conditional logic.
Problem code:
function processValue(value: string | number) {
if (typeof value === "string") {
return value.toUpperCase();
} else if (typeof value === "number") {
return value.toFixed(2);
}
// TypeScript infers 'value' is never here
const result: string = value; // Error: Type 'never' is not assignable to type 'string'
return result;
}Fix: Remove unreachable code or add proper type assertion:
function processValue(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
} else {
return value.toFixed(2);
}
// No unreachable code
}Generic functions like array methods may infer never when the type cannot be determined from context.
Problem:
const result = [].reduce((acc, item) => {
acc[item] = item; // Error: never type
return acc;
}, {});Fix with explicit types:
interface Result {
[key: string]: string;
}
const result = [].reduce<Result>((acc, item: string) => {
acc[item] = item;
return acc;
}, {});Or provide initial type:
const items: string[] = [];
const result = items.reduce((acc, item) => {
acc[item] = item;
return acc;
}, {} as Record<string, string>);If you know a value cannot actually be never at runtime, use type assertion as an escape hatch.
When TypeScript over-narrows:
function handleEvent(event: "click" | "hover") {
if (event === "click") {
// handle click
} else if (event === "hover") {
// handle hover
} else {
// TypeScript thinks this is unreachable (event is never)
// But if you're adding new event types, this might execute
const eventType: string = event as string; // Safe assertion
console.warn(`Unknown event: ${eventType}`);
}
}Caution: Only use assertions when you understand why TypeScript inferred never and you're certain the code is correct.
With discriminated unions, failing to handle a case can result in never inference.
Problem:
type Response =
| { status: "success"; data: string }
| { status: "error"; message: string };
function handleResponse(response: Response) {
if (response.status === "success") {
return response.data;
}
// Forgot to handle "error" case
const msg: string = response.message; // Error: Property 'message' does not exist on type 'never'
}Fix:
function handleResponse(response: Response): string {
if (response.status === "success") {
return response.data;
} else {
return response.message; // Now TypeScript knows this is the error case
}
}The TypeScript compiler option noImplicitAny helps prevent never type inference issues by requiring explicit types.
Update tsconfig.json:
{
"compilerOptions": {
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true
}
}With noImplicitAny enabled, TypeScript will error on ambiguous empty arrays rather than silently inferring never[], forcing you to add explicit types:
// Will error without type annotation when noImplicitAny is true
const items: string[] = []; // Must explicitly typeThis makes type errors surface earlier in development rather than when you try to use the values.
Advanced notes
Understanding never in the Type System
The never type is TypeScript's bottom type, meaning it's a subtype of every other type. Paradoxically, never is assignable to any type, but no type (except never itself) is assignable to never. This makes it useful for representing impossible states and exhaustiveness checking.
Empty Array Type Inference History
The inference of never[] for empty arrays has been debated in the TypeScript community (GitHub issues #18687, #20946, #51979). With strictNullChecks enabled, TypeScript cannot default to any[] or undefined[], so it chooses never[] to force developers to make explicit type decisions. While this prevents some bugs, it can be frustrating for beginners.
Library-Specific Issues
This error frequently appears in library contexts with complex generics:
- react-hook-form: useFieldArray can infer never for field names if types aren't properly constrained
- Redux: Action type inference sometimes resolves to never with incorrect reducer typing
- Styled-components: Variant props can infer never when extending component types
Exhaustiveness Checking Pattern
A common intentional use of never is for exhaustiveness checking in switch statements:
type Shape = Circle | Square | Triangle;
function area(shape: Shape): number {
switch (shape.kind) {
case "circle": return Math.PI * shape.radius ** 2;
case "square": return shape.size ** 2;
case "triangle": return (shape.base * shape.height) / 2;
default:
const _exhaustive: never = shape; // Compile error if we add a new Shape
return _exhaustive;
}
}If you add a new shape type without handling it, TypeScript will error because the new type is not assignable to never.
Control Flow Analysis Limitations
TypeScript's control flow analysis is sophisticated but not perfect. It may not understand complex runtime logic, especially with:
- Indirect type guards through helper functions
- Complex boolean logic with multiple conditions
- Type predicates that don't narrow correctly
In these cases, explicit type annotations or assertions may be necessary even when the code is logically sound.
Frequently asked questions
- What does "Type 'never' is not assignable to type 'string'" mean?
- The "Type 'never' is not assignable to type 'string'" error indicates that TypeScript has determined a value should be of type never (a type representing values that never occur) but you're trying to use it in a context expecting a string. The never type in TypeScript represents the type of values that never occur. When TypeScript infers never, it's typically because type narrowing through control flow analysis has eliminated all possible types, or because an empty array was declared without explicit typing, leading TypeScript to infer never[].
- How do I fix "Type 'never' is not assignable to type 'string'"?
- This error occurs when TypeScript infers a variable as the never type (representing impossible values) but you try to assign or use it where a string is expected, commonly from untyped empty arrays or over-narrowed type guards.
- What causes "Type 'never' is not assignable to type 'string'"?
- Empty array declared without explicit type annotation, causing TypeScript to infer never[] Type narrowing through if/else or switch statements eliminates all possible union members Incorrect type guards that narrow a type to an impossible state
- Is the "Type 'never' is not assignable to type 'string'" 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
- ๐Typescriptlang.org - narrowing.html(Official Docs)
- ๐Typescriptlang.org - everyday-types.html(Official Docs)
- ๐Github.com - 51979(GitHub)
- ๐Github.com - 20946(GitHub)
- ๐
- ๐
- ๐Github.com - 31663(GitHub)
- ๐Github.com - 16762(GitHub)