This TypeScript error occurs when TypeScript infers a type as 'never' (representing an impossible or unreachable state) and attempts to use it where it's incompatible with a function parameter. The 'never' type is assignable to all other types, but attempting to pass 'never' to a parameter that expects a specific type can indicate a logic error. The fix involves understanding why TypeScript inferred 'never' and restructuring type constraints or narrowing logic.
TypeScript infers the 'never' type when it determines that a value or expression can never occur—it represents an impossible state. When this occurs in a context where a function parameter expects a concrete type, you have a compatibility mismatch. The 'never' type is the bottom type in TypeScript's type system, meaning no other type (except never itself) can be assigned to it. This error typically signals a logical issue in how you've structured union types, type narrowing, or generic type constraints. TypeScript is protecting you from code paths that should never execute.
Look at the error message to find the exact line and context. The error typically occurs at a function call where an argument has been narrowed or inferred as 'never'.
// Example: Narrowing exhausts all union types
type Status = "success" | "error";
function handle(status: Status) {
if (status === "success") {
console.log("Success");
} else if (status === "error") {
console.log("Error");
} else {
// At this point, status has type 'never'
const impossible: never = status; // This is correct
}
}
function process(value: never) {
// This function can never be called with a real value
}
const x: never = /* impossible to create */;
process(x); // Error: Argument of type 'never' is not compatibleReview the conditional branches or type guards that led to the 'never' type. In many cases, the issue is that you've narrowed a union type to exhaustion, and TypeScript correctly identifies that the remaining code path should be unreachable.
// Example with discriminated union:
type Result =
| { status: "success"; data: string }
| { status: "error"; error: Error };
function handleResult(result: Result) {
if (result.status === "success") {
console.log(result.data);
} else if (result.status === "error") {
console.log(result.error);
} else {
// result has type 'never' here—this is unreachable and correct
const exhaustive: never = result;
}
}If the error involves generics, check that your type parameters and constraints don't create impossible combinations. Sometimes conflicting constraints can result in 'never'.
// Example: Impossible generic constraint
function getValue<T extends string & number>(value: T): T {
// No type can be both string AND number, so T resolves to 'never'
return value;
}
// Better approach: Use union instead of intersection for multiple possibilities
function getValue<T extends string | number>(value: T): T {
return value;
}
getValue("hello"); // OK
getValue(42); // OKIf your function is declared to accept 'never', consider whether this is intentional. A function that accepts only 'never' can never be called with a real value. Change the parameter type to match what you actually need to accept.
// Before: Function can never be called
function impossible(value: never): void {
console.log(value);
}
// After: Accept the actual type you need
function possible(value: string | number): void {
console.log(value);
}
possible("text"); // Now works
possible(42); // Now worksIn cases where you've correctly exhausted all cases and are assigning to a 'never' variable, you can use this as a compile-time exhaustiveness check. This is a valid pattern.
type Action = "read" | "write" | "delete";
function handleAction(action: Action) {
if (action === "read") {
console.log("Reading");
} else if (action === "write") {
console.log("Writing");
} else if (action === "delete") {
console.log("Deleting");
} else {
// Exhaustiveness check: if you add a new Action type,
// TypeScript will error here because action won't be 'never'
const exhaustive: never = action;
}
}Run TypeScript compiler to confirm the error is resolved.
npx tsc --noEmitIf errors remain, revisit your type constraints and narrowing logic to ensure they match your actual usage.
The 'never' type is a fundamental part of TypeScript's type system and represents the type of values that can never occur. Unlike 'void' (which represents the absence of a value), 'never' represents an impossible value. The key distinction: 'never' is assignable to every type, but no type is assignable to 'never' (except never itself). This makes 'never' useful for exhaustiveness checking in discriminated unions and switch statements. If you encounter 'Argument of type never is not compatible' errors, it's often a signal that your type narrowing is correct and working as intended—TypeScript is protecting you from unreachable code. However, if this appears in production code unexpectedly, it may indicate that your union types, constraints, or function signatures need revision. When working with libraries or complex generic code, understanding how TypeScript resolves type parameters to 'never' is essential for debugging these issues. The 'satisfies' operator (TypeScript 4.9+) can help provide additional type inference hints when 'never' seems to be appearing unexpectedly.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript