# @typescript-eslint/no-misused-promises

> Disallow promises where the code around them cannot handle one

A promise is an object, so it's always truthy, and `if (isAdmin(user))` without `await` always takes the branch. An `async` function passed where a callback should return nothing is never awaited, so `forEach` moves on before the work is done, and nothing catches a rejection. A promise spread into an object adds no properties.

`bun lint --type-aware` turns this rule on in TypeScript files.

{/* Generated by src/codegen/lint-rule-docs.ts. Do not edit this section. */}

## Configure

Off by default. This rule needs types, so turning it on makes `bun lint` type check your code first.

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/no-misused-promises" = "error" # or "warn"
```

Every option, set to its default:

```toml bunfig.toml
[lint.rules]
"@typescript-eslint/no-misused-promises" = ["error", {
  checksConditionals = true,
  checksVoidReturn = {
    arguments = true,
    attributes = false,
    inheritedMethods = true,
    properties = true,
    returns = true,
    variables = true,
  },
  checksSpreads = true,
}]
```

{/* End of the generated section. */}

## Examples

Reported:

{/* bad {"count": 3} */}
```ts
declare function isAdmin(id: string): Promise<boolean>;
declare function remove(id: string): Promise<void>;
declare function load(id: string): Promise<{ name: string }>;

function cleanUp(ids: string[]) {
  if (isAdmin(ids[0])) {
    ids.forEach(async id => {
      await remove(id);
    });
  }
  return { id: ids[0], ...load(ids[0]) };
}
```

Not reported:

{/* good */}
```ts
declare function isAdmin(id: string): Promise<boolean>;
declare function remove(id: string): Promise<void>;
declare function load(id: string): Promise<{ name: string }>;

async function cleanUp(ids: string[]) {
  if (await isAdmin(ids[0])) {
    for (const id of ids) {
      await remove(id);
    }
  }
  return { id: ids[0], ...(await load(ids[0])) };
}
```

An `async` callback in `filter` keeps every item, because the promise it returns is truthy:

{/* bad */}
```ts
declare function isAdmin(id: string): Promise<boolean>;

const admins = ["ada", "lin"].filter(async id => await isAdmin(id));
```

## Options

| Option | Default | What it does |
| --- | --- | --- |
| `checksConditionals` | `true` | Report a promise as a condition: in `if`, `while`, `? :`, `!`, `&&`, `\|\|`, and returned from the callback of `filter`, `find`, `some` and the like. |
| `checksVoidReturn` | `{ "attributes": false }` | Report a function that returns a promise where a function that returns `void` is expected. |
| `checksSpreads` | `true` | Report `...` in front of a promise. |

`checksVoidReturn` is `true`, `false`, or an object that turns the check off in some places. A key you leave out is `true`.

JSX attributes aren't checked by default, because `<form onSubmit={save}>` with an `async` function is how most React code handles events. With an ESLint config file the default is typescript-eslint's, `true`.

| Key | Where the function is |
| --- | --- |
| `arguments` | An argument of a call or of `new`. |
| `attributes` | A JSX attribute. |
| `inheritedMethods` | A method, when the class or interface it extends or implements declares it as returning `void`. |
| `properties` | A property of an object. |
| `returns` | A value that a function returns. |
| `variables` | A value assigned to a variable. |

Not reported with `checksVoidReturn: { arguments: false }`:

{/* good {"options": [{"checksVoidReturn": {"arguments": false}}]} */}
```ts
declare function remove(id: string): Promise<void>;

function cleanUp(ids: string[]) {
  ids.forEach(async id => {
    await remove(id);
  });
}
```

Not reported by default, and reported with `checksVoidReturn: true`:

{/* good */}
```tsx
declare namespace JSX {
  interface IntrinsicElements {
    form: { onSubmit?: () => void };
  }
}
declare function save(): Promise<void>;

const form = <form onSubmit={save} />;
```

{/* bad {"options": [{"checksVoidReturn": true}]} */}
```tsx
declare namespace JSX {
  interface IntrinsicElements {
    form: { onSubmit?: () => void };
  }
}
declare function save(): Promise<void>;

const form = <form onSubmit={save} />;
```

`checksConditionals` also takes `{ "flagUnions": .. }`, for a condition that's only sometimes a promise. With `"none"` (default) it's allowed. With `"all"` it's reported. With `"strict"` it's reported if the union has both the promise and what it resolves to, like `number | Promise<number>`.

Not reported by default:

{/* good */}
```ts
declare function cached(key: string): number | Promise<number>;

if (cached("total")) {
  console.log("found");
}
```

Reported with `checksConditionals: { flagUnions: "strict" }`:

{/* bad {"options": [{"checksConditionals": {"flagUnions": "strict"}}]} */}
```ts
declare function cached(key: string): number | Promise<number>;

if (cached("total")) {
  console.log("found");
}
```
