相关文章推荐
呐喊的键盘  ·  Java HttpClient ...·  1 年前    · 
没读研的火柴  ·  javascript - ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm building an API in typescript and some controller actions can be synchronous while others can't. I'd like to specify a response type like so:

type ActionResult =IHttpActionResult | Promise<IHttpActionResult>;

Then, as I'm building actions, when they become promise based, I can just prepend async and be done with it.

But, typescript complains that "the return type of an async function or method must be the global Promise type."

Why can't an async function return a union of T | Promise<T>?

Here's an example:

type StringPromise = Promise<string>;
// These two work as you'd expect
async function getHello(): Promise<string> {
    return 'hello';
async function getGoodbye(): StringPromise {
    return 'goodbye';
type StringyThingy = string | Promise<string>;
// the next two work as you would expect them to
function getHoorah(): StringyThingy {
    return 'hoorah!';
function getWahoo(): StringyThingy {
  return new Promise(resolve => resolve('wahoo'));
// This one results in the error:
// "the return type of an async function or method must be the global Promise type."
async function getSadface(): StringyThingy {
  return ':(';

Here are some sample outputs for the code above:

getHello().then(console.log);
getGoodbye().then(console.log);
console.log(getHoorah());
// The library I'm using is probably using typeguards for this
// I'd imagine
const wahoo = getWahoo();
if (typeof(wahoo) === 'string') {
  console.log(wahoo);
} else {
  wahoo.then(console.log);

The async notation is syntactic sugar for: "This function will always return a promise."

Even if you declare it as such:

const foo = async() => 3;

It's basically the same (though more strict) as:

const foo = () => new Promise(resolve => resolve(3));

or as:

const foo = () => Promise.resolve(3);

All of these examples will return a Promise.

The main difference is, that "normal" functions can return both a Promise and other types, yet once async is used it, it always will return a promise.

Even if a promise resolves immediately, there is no way for an async function to NOT return a promise by design.

You'll have to await it / use then on it.

This is also stated on mozilla's JavaScript reference about the async keyword:

The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.

And specifically on the return type:

A Promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.

With that in mind, I recommend making your API async per default. It doesn't matter to the outside world if some of your actions are synchronous. You can resolve the promise right away in that case. There is no need for your type StringyThingy = string | Promise<string>;

Type against Promise<string> and let async handle the wrapping into promise for you or actually return other promises in the real async use-case. That way you don't have to check for instance of promise, but you'll handle both the async / sync branch the same way.

If you really want the union type (I really don't recommend this), then you have to give up the usage of the async keyword.

You can define normal functions that return either type:

const foo = (x:number): Promise<number>|number => {
    if(x >=0) {
         return new Promise(resolve => resolve(x));
    } else {
         return x;
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.