-1

How to?

Without async example.

Playground.

// cannot be changed
declare type NextApiRequest = {
    query: {
        [key: string]: string | string[];
    };
    cookies: {
        [key: string]: string;
    };
    body: any;
};

interface NextApiRequestEx<T> extends NextApiRequest {
  body: T;
}

type Bar = { bar: string };

const isValid = async <T>(req: NextApiRequest): req is NextApiRequestEx<T> => true;

declare const req: NextApiRequest;

if (isValid<Bar>(req)) {
  req.body.bar 
}

error:

The return type of an async function or method must be the global Promise type.

5
  • 1
    The error message explains what the problem is. Is there a question in here somewhere? Commented Dec 26, 2019 at 19:22
  • You've typed your function as a boolean-returning typeguard. Async functions must return a Promise<...> in typescript because they are actually guaranteed to do so regardless of what code you put in the function. Commented Dec 26, 2019 at 19:22
  • emm, and how can i do it with promise? Commented Dec 26, 2019 at 19:23
  • 2
    I don't believe async typeguards are a feature of typescript. Make your typeguard synchronous and have it take in whatever async results it needs directly Commented Dec 26, 2019 at 19:24
  • @CollinD thanks, please answer not in comments so i can accept it. Commented Dec 26, 2019 at 19:25

1 Answer 1

2

Functions that are tagged async must be typed as returning a promise, since JS guarantees that the function will return a promise when invoked, regardless of its body.

This is a little bit more complex because you are using a typeguard, which cannot be async. One strategy to deal with this is to make your typeguard synchronous and have it take in pre-awaited results that it might otherwise await.

As an example

// what we'd like to do, obviously a contrived example
async isSomething(t: Something | OtherThing): t is Something {
  const result = await someCall(t); // some async result we need to determine what t is
  return result.isSomething;
}

This could be changed up to

async isSomethingAsyncPart(t: Something | OtherThing): IsSomethingAsyncResultSet {
  // do some await'ing here
  return asyncResults; 
}
isSomethingGuard(t: Something | OtherThing, asyncResults: IsSomethingAsyncResultSet): t is Something {
  // some synchronous evaluation using t and/or asyncResults
}

// kinda yucky but :shrug_emoji:
if (isSomethingGuard(t, await isSomethingAsyncPart(t)) { . . .}

Not sure this is the best way to handle stuff (typeguards requiringg async work seems a little suspect overall, honestly). You may be trying to shoehorn the type system into doing something it isn't designed for.

If your typeguard really is just () => true, you could just make it not async as well.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.