Function lacks ending return statement Error in TS

avatar

Borislav Hadzhiev

Last updated: Mar 1, 2022

banner

Photo from Unsplash

Function lacks ending return statement Error in TS #

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.

index.ts
// ⛔ 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.

index.ts
// ✅ 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>.

index.ts
// ⛔ 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>.

index.ts
// ✅ 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.

index.ts
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.

index.ts
// ⛔ 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.

To solve this, we have to replace the ending else if statement with an else or simply remove the condition.

The following 2 examples are the same.

index.ts
// ✅ Works now const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } else { return 'bye'; } };

Or remove the else block completely.

index.ts
// ✅ 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.

index.ts
// ⛔ 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.

index.ts
// ✅ Works now const getString = (): string => { if ('hello'.length === 5) { return 'hello'; } function inner() { return 'bye'; } return inner(); };

Conclusion #

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.

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.
book cover
You can use the search field on my Home Page to filter through all of my articles.