How do you type an async function return in TypeScript?

This tests if you know async functions always return Promise<T>. A great answer: annotate Promise<User>, return User from the body, and note TypeScript implicitly wraps it. A red flag is omitting Promise and typing the return as just User.
What's really being asked
Whether you understand that the async keyword changes both the runtime behavior and the static type of a function. Specifically, it checks if you know that an async function's return type annotation must explicitly include the Promise generic, even though the value you return inside the function body is not itself a Promise. Interviewers want to see that you grasp the distinction between what you write in the return statement and what the caller actually receives.
The full answer
First, the correct signature is async function fetchUser(id: string): Promise<User>. Second, inside the function you can simply return user where user has type User, and the TypeScript compiler will implicitly treat the function as returning Promise<User>. Third, if you try to annotate the return type as just User, TypeScript will report an error because the async keyword guarantees a Promise is returned at runtime. Fourth, if the function body has no return statement, the resolved value is undefined so the type becomes Promise<void>. Fifth, if you throw an error or reject, the Promise rejects and the caller should handle that with try catch or .catch.
The mistakes people make
Annotating the return type as User instead of Promise<User>. Manually returning Promise.resolve(user) inside an async function to satisfy the type checker, which is redundant because async already does this wrapping. Claiming that TypeScript strips the Promise wrapper or that await inside the function changes the outer return type. Also, saying you can return Promise<User> from inside the body and that it unwraps automatically; while returning a Promise inside an async function is legal, it results in a double wrapped Promise<Promise<User>> at the type level unless flattened by the type system, though at runtime JavaScript flattens it.
What usually comes next
How does error handling affect the return type? The answer is that thrown errors become rejected Promises, so the return type alone does not capture failure; you might discuss Promise<User> versus a Result type. What happens if you return a Promise inside an async function? The answer is that it gets flattened at runtime but TypeScript may infer a nested Promise type unless you await it first. How would you type a function that sometimes returns null? You would write Promise<User | null>.
A concrete example
Consider async function fetchUser(id: string): Promise<User> { const res = await fetch(/api/users/${id}); const data = await res.json(); return data as User; }. The return statement hands back a User object, but the caller receives Promise<User>. If you wrote return await fetch(...) without parsing, the type would be Promise<Response>. If you accidentally annotated the function as User and wrote return data, TypeScript would error with Type User is not assignable to type Promise<User>.
Interview question
How do you correctly annotate and implement the return of an async function that yields a User object?
- a.Annotate the return type as Promise<User> and return a User value from the bodyCorrect
- b.Annotate the return type as User and return Promise.resolve(user) from the body
- c.Annotate the return type as User and return a User value from the body
- d.Annotate the return type as Promise<User> and return Promise.resolve(user) from the body
Why? this is the answer
An async function implicitly wraps the returned value in a Promise, so the annotation must be Promise<User> while the body simply returns User. Option C is wrong because omitting Promise causes a type error, and Option D is redundant because async already wraps the return value, which can create a nested Promise type.
Just read this? Test yourself on what you have been reading.
Read the original → developer.mozilla.org
- #typescript
- #async-await
- #promises
- #type-system
You just looked this up. Could you explain it out loud?
That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on typescript — each one lists the topics its interview covers.
See open roles