Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
lang lang/typescript/async/no-floating-promise.md medium

typescript-no-floating-promise

禁 floating promise — 必 await 或显式 .catch。Use when 写 TS 业务代码 / 评审涉及 `no-floating-promise` 的 PR。

promiseawaitfloating promiseunhandled或显式
paths
  • frontend/**/*.ts
  • frontend/**/*.tsx

TypeScript · 禁 floating promise

规则

任何 Promise 必须被 await.then.catchvoid 或显式赋值。游离的 Promise 在错误时会触发 unhandled rejection,难以追溯。

ESLint 配置

{
  "rules": {
    "@typescript-eslint/no-floating-promises": "error"
  }
}

反例 → 正例

// ❌ floating — 错误被吞
async function clickHandler() {
  saveSlide(data);   // 没 await
}

// ✅ await
async function clickHandler() {
  await saveSlide(data);
}

// ✅ 故意 fire-and-forget — 加 void 表态
void saveAnalytics(event);

// ✅ 显式处理失败
saveSlide(data).catch(err => toast.error(err.message));

在事件回调里

// ❌ React 事件回调声明同步,body async 调用没 await
<Button onClick={() => saveSlide(data)} />

// ✅ 加 void
<Button onClick={() => { void saveSlide(data); }} />

// ✅ 或者 async 回调(注意:React 不等待)
<Button onClick={async () => {
  try { await saveSlide(data); }
  catch (e) { toast.error(e.message); }
}} />

在 useEffect 里

// ❌ useEffect 的回调不能 async
useEffect(async () => {
  await fetchData();
}, []);

// ✅ 内部包一层
useEffect(() => {
  void (async () => {
    try { await fetchData(); }
    catch (e) { ... }
  })();
}, []);

// ✅ 更好:用 TanStack Query 替代 useEffect 拉数据

Promise.all / allSettled

// 多个并发 promise — 同样不能游离
const [a, b, c] = await Promise.all([fetchA(), fetchB(), fetchC()]);

// 允许部分失败用 allSettled
const results = await Promise.allSettled([...]);
results.forEach(r => {
  if (r.status === "rejected") logger.warn("partial failure", r.reason);
});

自检

  • [ ] ESLint no-floating-promises 全绿?
  • [ ] 事件回调 / setTimeout 内的 async 都用 void
  • [ ] useEffect 内不直接 async,包了一层 IIFE 或用 useQuery?

相关