JSDoc tag

@async

  • Not checked by TypeScript
  • Tested with TypeScript 5.9

@async is a JSDoc documentation tag for a function that runs asynchronously. TypeScript 5.9 ignores it: a function tagged @async that returns a string still has the return type string, and calling .then() on its result is an error.

TypeScript gets the same information from the code itself. An async function always returns a promise, and @returns {Promise<T>} says what the promise resolves to. The handbook names @async as an example of a tag TypeScript does not support.

At a glance

Use JSDoc in a .js file TypeScript in a .ts file
An async function /** @returns {Promise<string>} */ async function load() { … } async function load(): Promise<string> { … }

Examples

load.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: load.js(7,3): error TS2322: Type 'string' is not assignable to type 'Promise<string>'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. load.js(7,3): error TS2322: Type 'string' is not assignable to type 'Promise<string>'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. load.js(7,3): error TS2322: Type 'string' is not assignable to type 'Promise<string>'. checked 21 October 2026
/**
 * @async
 * @returns {Promise<string>}
 */
export function loadGreeting() {
  return "hello";error TS2322: Type 'string' is not assignable to type 'Promise<string>'.
}
@async does not make a function return a promise.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
load.js load.ts TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @param {string} url
 * @returns {Promise<string>}
 */
export async function loadText(url) {
  const response = await fetch(url);
  return response.text();
}

loadText("/greeting.txt").then((text) => text.trim());
export async function loadText(url: string): Promise<string> {
  const response = await fetch(url);
  return response.text();
}

loadText("/greeting.txt").then((text) => text.trim());
The async keyword is what makes the return type a promise.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

How we tested it

The failing example tags a plain function @async, declares @returns {Promise<string>} and returns a string. If TypeScript read @async, the string would be wrapped in a promise and the return would be fine. tsc reports TS2322 instead ("Type 'string' is not assignable to type 'Promise<string>'"), so the tag is not read.

Typing async functions

Write the async keyword and describe the resolved value with @returns {Promise<T>}. Without the tag, TypeScript infers the promise type from the return statements, which is often enough for small functions.

The return type of an async function must be a Promise type. @returns {boolean} on an async function is an error (TS1064), and the message suggests the Promise<boolean> you meant.

Gotchas

  • Returning a promise from a non-async function is fine: function load() { return fetch(url); } is typed as returning Promise<Response> with or without any tag.
  • Inside an async function, return value and return Promise.resolve(value) produce the same type; TypeScript unwraps nested promises with Awaited.

Questions

Do I need @async if I use the async keyword?

No. TypeScript reads the keyword. Keep @async only if a documentation tool you run needs it; it does no harm, but it does nothing for checking.

Sources

Last reviewed 20 October 2026.