TypeScript is weirdly smart with async functions

Sure, we know async functions let us wait for data, but what happens if you return a value that requires no waiting at all? If you want to early-exit an async function by just returning a static value which was immediately ready, will that value need to be wrapped in a Promise? I thought so but it turns out not-let me explain!
Example Code
Full Function
async function example(): Promise<string> {
if (testValue) {
return "local string";
}
return await fetchString(requiredParam);
}
Expected Problem
It looks like the function returns a Promise that resolves to a string which is either local or fetched, but the type definition only says Promise would be accepted. Considering this, we might have expected a type error here:
// ...
if (!requiredParam) {
// Expected error: Type 'string' is not assignable to type 'Promise<string>'.
return "local string";
}
// ...
Shouldn't we have been forced to wrap the returned local string in a Promise?
Expected Solution
//...
if (!requiredParam) {
// Attempt to avoid error: wrap the local string in a Promise.
return Promise.resolve("local string");
}
//...
Results
JavaScript automatically wraps the return values of async functions in Promises! Even if the promise wasn't specified within the function itself, the types are automatically handled. In the synchronous branch of the function where return "local string" exists, JavaScript internally converts it to Promise.resolve("local string"), preserving the correct typing. This behavior ensures that async functions always fulfills their type definition of a Promise regardless of whether the particular logic branch which executed was 'promise-ful.' The automatic wrapping of returned values in Promises both aligns with TypeScript's type system and-not for nothing-simplifies developer experience. This is so much better than needing to write the boilerplate of wrapping non-promise values in a Promise. Ironic to have spent so much time considering a feature meant to save time, but this was my first time noticing TypeScript behave incoherently with strict typing. That said, far be it from me to turn my nose up at that, and I'd be glad to stumble across more exceptions like this one!


