Think you know async functions? Check out this resolve behavior.

James Mitofsky
2 min readJan 28, 2024
Panda scientist choosing between two choices.

Async functions are used to wait for data, but what happens if you return a value that didn’t require any waiting at all?

If you want to early-exit a function by just returning a static value which was immediately ready, will that value need to be wrapped in a Promise? Let’s see!

Code Example

import { fetchFromRemote, requiredParam } from 'package'

const myFunc = async (): Promise<string> => {
if (!requiredParam) {
const localString = "local string";
return localString;
}
const fetchedString = await fetchString(requiredParam);
return fetchedString;
}

Breaking Expectations

The function returns a Promise that resolves to EITHER a local string or a fetched string, but the type definition said only Promise would be acceptable. Considering this, we might have expected a type error here:

if (!requiredParam) {
const localString = "local string";
return localString; // Expected error: Type 'string' is not assignable to type 'Promise<string>'.
}

Shouldn’t we have been forced to wrap the returned local string in a Promise?

if (!requiredParam) {
const localString = "local string";
const localPromise = Promise.resolve(localString); // Attempt to avoid error: wrap the local string in a Promise.
return localPromise;
}

The Answer

No! JavaScript automatically wraps the return values of async functions in Promises, even if it wasn’t specified within the function itself. So, in the synchronous branch where return "local string" is encountered, JavaScript internally converts it to Promise.resolve("local string"). This behavior ensures that regardless of the code path, the async function always fulfills its type definition of returning a Promise.

This automatic wrapping of values in Promises not only aligns with TypeScript’s type system but also simplifies the development process. Developers can write asynchronous functions more intuitively without explicitly wrapping each return value in a Promise, leading to cleaner and more concise code.

--

--