Borislav Hadzhiev
Tue Mar 01 2022·3 min read
Photo by Lê Tân
The "Function lacks ending return statement and return type does not include
undefined" error occurs when not all code paths of a function with an explicit
return type return a value. To solve the error, return a value from all code
paths or include undefined
in the function's return type.
Here are 3 common examples of how the error occurs.
// ⛔ Error:️ Function lacks ending return statement // and return type does not include 'undefined'.ts(2366) const getNumber = (): number => { if (Math.random() > 0.5) { return 100; } // 👇️ No return value here 👇️ }; const getPromise = async (): Promise<number> => { try { const result = await Promise.resolve(42); return result; } catch (err) { console.log(err); // 👇️ No return value here 👇️ // TypeScript expects that all calls to function // return number (even erroneous ones) } }; const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } else if ('hello'.length === 6) { return 'hello'; } // 👇️ TypeScript doesn't know that 👇️ // getting here is impossible };
Let's look at the solutions to the 3
causes of the error.
In the first example, we've explicitly set the function's return type to
number
, but not all code paths return a value.
To solve this error, make sure to return a value from all of the function's code paths.
// ✅ Works now const getNumber = (): number => { if (Math.random() > 0.5) { return 100; } return 50; // 👈️ all code paths return a value };
The second example shows how the error occurs when using a try/catch
statement
in a function, for which we've set a return type of Promise<number>
.
// ⛔ Error:️ Function lacks ending return statement // and return type does not include 'undefined'.ts(2366) const getPromise = async (): Promise<number> => { try { const result = await Promise.resolve(42); return result; } catch (err) { console.log(err); // 👇️ no return value here 👇️ } };
The problem here is that we've typed the function to return Promise<number>
,
so TypeScript expects all of the calls to the function to return
Promise<number>
, even the ones that error out.
To solve this, use a
union type
to set the function's return type to Promise<number | undefined>
.
// ✅ Works now const getPromise = async (): Promise<number | undefined> => { try { const result = await Promise.resolve(42); return result; } catch (err) { console.log(err); } };
Now TypeScript knows that the function returns a Promise of type number
or
undefined
, which is an accurate representation of the function's return type.
When you get the return value of the function, use a
type guard to
determine if it's a number
or undefined
.
const getPromise = async (): Promise<number | undefined> => { try { const result = await Promise.resolve(42); return result; } catch (err) { console.log(err); } }; getPromise().then((value) => { if (typeof value === 'number') { // ✅ We know that value is number console.log(value.toFixed()); } });
A simple if
statement in which we used the
typeof operator
serves as a type guard.
TypeScript knows that the type of value
is a number
in the if
block, so we
can safely access number-related built-in methods.
The third example shows how TypeScript is not always able to accurately determine the flow of a function.
// ⛔ Error:️ Function lacks ending return statement // and return type does not include 'undefined'.ts(2366) const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } else if ('hello'.length === 6) { return 'hello'; } // 👇️ TypeScript doesn't know that 👇️ // getting here is impossible };
The string hello
has a length of 5
, so we know that the if
block will run
and we will always return the value hello
, but TypeScript doesn't know.
else if
statement with an else
or simply remove the condition.The following 2 examples are the same.
// ✅ Works now const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } else { return 'bye'; } };
Or remove the else
block completely.
// ✅ Works now const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } return 'bye'; };
Either way, TypeScript is now able to determine that all of the function's code
paths return a value of type string
.
A common cause of the error is - we return a value from an inner function or a callback and think that the value also gets returned from the outer function.
// ⛔ Error:️ Function lacks ending return statement // and return type does not include 'undefined'.ts(2366) const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } function inner() { return 'bye'; } inner(); };
Notice that the inner
function also returns a string
, but returning a value
from a nested function doesn't mean the value gets returned from the outer
function.
If you are in a similar situation, make sure to return the result of calling the inner function.
// ✅ Works now const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } function inner() { return 'bye'; } return inner(); };