error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. is reported when a function's return type is declared, by @returns or by a @type tag on the function, and its body contains no return statement with a value at all. In a .js file the error is reported on the type inside the JSDoc tag.
The usual cause is a function that computes its result and forgets to hand it back. A less obvious one is a @type tag that types the whole function, such as a framework's handler type with a non-void return; the Express handler recipe shows that case.
At a glance
| Code | TS2355 |
|---|---|
| Message | A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value. |
| TypeScript's category | error |
| Listed under | Types do not match |
| Turned on by | No option: every checked file reports it |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0).
What it looks like
/** @param {string} title @returns {string} */error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.
export function slugify(title) {
title.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-");
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} What causes it
- The body does the work but never says
return value(a.map,.replaceor template string whose result is dropped). - A
@typeon a function expression or arrow function declares a function type whose return type is notvoid, and the body is written as if it returns nothing.
How to fix it
Return the value
Add the return. In the example the string methods produce a new string and the function drops it.
/**
* @param {string} title
* @returns {string}
*/
export function slugify(title) {
return title.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-");
}
/**
* @param {string} title
* @returns {void}
*/
export function logTitle(title) {
console.log(title.trim());
}jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": ["*.js"]
} Or declare that the function returns nothing
If the function is called for its side effect, change the tag to @returns {void}, or remove @returns and let the checker infer void. For a handler typed with @type, use @param tags or @satisfies instead, so the return type comes from the body.
Gotchas
- If some paths return a value and others fall off the end, the error is TS2366 instead.
@returns {Promise<string>}on anasyncfunction requires areturnwith a string; anasyncfunction that only awaits work isPromise<void>.
Sources
- JSDoc Reference: @returns · TypeScript handbook
- More on Functions: Return type void · TypeScript handbook
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 20 October 2026.