This TypeScript error occurs when you try to return a value from a function explicitly annotated with a void return type. The void type indicates a function should not return any value.
This error appears when TypeScript detects that you're attempting to return a value from a function that has been explicitly declared with a `void` return type. The `void` type in TypeScript represents the absence of a return value and indicates that a function's purpose is solely to perform actions without producing data for the caller to use. Unlike languages where void might be loosely enforced, TypeScript strictly validates that void-typed functions do not return values. If you try to return a string, number, object, or any other value from a void function, TypeScript will report a type error like "Type 'string' is not assignable to type 'void'." It's important to understand that `void` is not the same as `undefined` in TypeScript. While a function that doesn't explicitly return anything will implicitly return `undefined` at runtime, the `void` type annotation is a compile-time contract stating that callers should not rely on or use any return value from the function.
First, locate the function causing the error. Look for functions with explicit : void annotations that contain return statements:
// ❌ Error: Type 'string' is not assignable to type 'void'
function logMessage(msg: string): void {
console.log(msg);
return "logged"; // This causes the error
}
// ❌ Error with arrow function
const handleClick = (): void => {
return true; // Cannot return boolean from void function
};Check your IDE's error messages to find the exact line where the return statement conflicts with the void type.
If the function is correctly typed as void and shouldn't return a value, simply remove the return statement or use return without a value:
// ✅ Correct: No return value
function logMessage(msg: string): void {
console.log(msg);
// No return statement, or use: return;
}
// ✅ Correct: Empty return for early exit
function processData(data: string | null): void {
if (!data) {
return; // Early exit without value
}
console.log(data);
}This is the appropriate fix when the function's purpose is to perform side effects (logging, updating state, etc.) without producing output.
If your function legitimately needs to return a value, update the return type annotation from void to the appropriate type:
// ✅ Changed from void to string
function formatMessage(msg: string): string {
const formatted = msg.toUpperCase();
return formatted;
}
// ✅ Changed from void to boolean
function validateInput(input: string): boolean {
return input.length > 0;
}
// ✅ For async functions returning data
async function fetchData(): Promise<string> {
const response = await fetch('/api/data');
return response.text();
}Let TypeScript infer the return type if you're unsure, then add the explicit annotation once confirmed.
For callback functions typed as void, remember that TypeScript allows implementations to return values (which will be ignored), but you cannot use those return values:
// ✅ This is allowed - callbacks can return values
type VoidCallback = () => void;
const callback: VoidCallback = () => {
return 42; // Allowed, but return value will be ignored
};
// Using the callback
const result = callback(); // result is typed as void, not number
// ❌ Cannot assign void to other types
const num: number = callback(); // Error!
// ✅ For event handlers in React/DOM
const handleClick = (): void => {
console.log('clicked');
// Don't return values from event handlers
};This contextual typing allows flexibility while preventing misuse of return values.
For async functions, ensure you're not returning values if typed as Promise<void>:
// ❌ Error: Type 'Promise<string>' is not assignable to 'Promise<void>'
async function saveData(): Promise<void> {
await delay(1000);
return "saved"; // Error!
}
// ✅ Correct: No return value
async function saveData(): Promise<void> {
await delay(1000);
console.log("Data saved");
// No return statement
}
// ✅ Correct: Return void explicitly if needed
async function saveData(): Promise<void> {
await delay(1000);
return; // Explicit void return
}
// ✅ If you need to return data, change the type
async function saveData(): Promise<string> {
await delay(1000);
return "saved successfully";
}Remember that Promise<void> means the promise resolves without a meaningful value.
When implementing interfaces or extending classes, ensure return types match:
interface Logger {
log(msg: string): void;
}
// ❌ Error: Cannot return value from void method
class FileLogger implements Logger {
log(msg: string): void {
this.writeToFile(msg);
return true; // Error! Interface specifies void
}
}
// ✅ Correct: No return value
class FileLogger implements Logger {
log(msg: string): void {
this.writeToFile(msg);
// No return
}
}
// ✅ Or create a separate method for status
class FileLogger implements Logger {
log(msg: string): void {
this.writeToFile(msg);
}
logWithStatus(msg: string): boolean {
this.writeToFile(msg);
return this.wasSuccessful();
}
}Consider whether you need to modify the interface/base class or adjust your implementation.
Contextual Void Typing: TypeScript has special rules for void in callback contexts. A function type with a void return type (() => void) can be implemented by a function that returns a value, but that value will be ignored by the type system. This design supports common patterns like Array.forEach where the callback's return value is intentionally ignored.
Void vs Undefined: While void and undefined might seem similar, they serve different purposes. A function returning void tells TypeScript "don't use the return value," while undefined is an actual value type. You cannot assign void to other types except void, undefined, null, any, and never.
ESLint Integration: The @typescript-eslint/no-confusing-void-expression rule can help catch misuses of void-returning functions, such as using them in expressions where a value is expected. This prevents subtle bugs where void values are unintentionally passed as arguments.
Promise<void> Patterns: In async code, Promise<void> is commonly used for operations that complete but don't produce a result (like saving data, sending notifications, or updating state). This is different from Promise<undefined> which explicitly resolves with undefined.
Working as Intended: Several GitHub issues have raised questions about TypeScript's void behavior, particularly around why implementations can return values from void-typed callbacks. The TypeScript team has confirmed this is intentional design to support flexible callback patterns while preventing misuse of return values.
Type parameter 'X' is not used in the function signature
How to fix "Type parameter not used in function signature" in TypeScript
Type parameter 'X' is defined but never used
How to fix "Type parameter is defined but never used" in TypeScript
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