623 words
3 minutes
Effect 类型安全错误处理:4 tryPromise:错误处理

Effect 的第一个优势是错误处理。

然而,Effect.promise 不处理错误

const main = Effect.flatMap(
  fetchRequest,
  jsonResponse
);

Effect.runPromise(main);

当你使用 Effect.promise 时,Effect 假设操作永远不会失败。实际上,main 的工作方式就像 Promise<unknown>,只是被包装在 Effect 中。

如果 Effect.promise 内部的函数抛出异常,那么执行 Effect 也会抛出异常! 👇

> effect-getting-started-course@1.0.0 dev
> tsx src/index.ts

node:internal/process/promises:289
            triggerUncaughtException(err, true /* fromPromise */);
            ^

SyntaxError: Unexpected token 'N', "Not Found" is not valid JSON

由于我们知道 fetch 可能失败,我们需要另一个函数:Effect.tryPromise

import { Effect } from "effect";

/// 👇 Effect<Response, UnknownException>
const fetchRequest = Effect.tryPromise(
  () => fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);

虽然 Effect.promise 返回 Effect<Response>,但 Effect.tryPromise 会收集任何错误并返回 Effect<Response, UnknownException>

错误类型#

什么是 UnknownException?为什么 Effect 现在有 2 个泛型参数?

当你执行任何普通的 TypeScript 函数时,你无法知道可能出现什么问题,除非你阅读函数实现

const request: Promise<Response> = fetch("https://pokeapi.co/api/v2/pokemon/garchomp/");

简单的例子:你怎么知道 fetch 是否会失败?requestPromise<Response>,所以不知道是否会出错,或者如何出错。

当你组合多个函数时,这个问题变得更加严重。

const main: Promise<unknown> =
  fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
    .then((response) => response.json());

由于 requestjson 都可能失败,你只有两个选择:

  1. 阅读所有函数的实现并检查任何 throw,然后用 try/catch 包装每个函数
const main = async (): Promise<unknown> => {
  let response;
  try {
    response = await fetch("https://pokeapi.co/api/v2/pokemon/garchomp/");
  } catch (e) {
    // fetch 错误:在这里做一些处理
    return;
  }

  try {
    return response.json();
  } catch (e) {
    // json 错误:在这里做一些处理
    return;
  }
};
  1. 将所有内容包装在单个 try/catch 中,并报告通用的”发生了某个错误”
const main = async (): Promise<unknown> => {
  try {
    const response = await fetch("https://pokeapi.co/api/v2/pokemon/garchomp/");
    return response.json();
  } catch (e) {
    // 某个地方发生了错误 💁🏼‍♂️
    return;
  }
};

Effect 通过在类型中直接提供错误来解决这个问题:

const fetchRequest: Effect<Response, UnknownException> = Effect.tryPromise(
  () => fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);

当我们组合 fetchRequestjsonResponse 时,我们得到一个返回 Effect<unknown, UnknownException> 的程序 main

  • unknown 是当一切正常工作时调用 response.json() 的返回类型
  • UnknownException 是当 fetchRequestjsonResponse 失败时的错误类型
/// Effect<Response, UnknownException>
const fetchRequest = Effect.tryPromise(
  () => fetch("https://pokeapi.co/api/v2/pokemon/garchomp/")
);

/// Effect<unknown, UnknownException>
const jsonResponse = (response: Response) => Effect.tryPromise(
  () => response.json()
);

/// Effect<unknown, UnknownException>
const main = Effect.flatMap(fetchRequest, jsonResponse);

Effect Playground

我们仍然无法区分 fetchRequestjsonResponse 中的错误,因为两者都被类型化为 UnknownException

别担心!tryPromise 还允许定义自定义错误,我们将在后续课程中学习如何实现。

Effect 类型安全错误处理:4 tryPromise:错误处理
https://0bipinnata0.my/posts/course/effect-beginners-complete-getting-started/type-safe-error-handling-with-effect/trypromise-error-handling/
Author
0bipinnata0
Published at
2025-08-30 13:18:37