477 words
2 minutes
[Effect Services] 01. 重构Effect代码

重构Effect代码#

https://github.com/typeonce-dev/effect-getting-started-course

到目前为止,我们在单个文件 index.ts 中实现了所有内容。

这个单文件开始看起来复杂:

index.ts

import { Config, Data, Effect, Schema } from "effect"; class Pokemon extends Schema.Class<Pokemon>("Pokemon")({ id: Schema.Number, order: Schema.Number, name: Schema.String, height: Schema.Number, weight: Schema.Number, }) {} class FetchError extends Data.TaggedError("FetchError")<{}> {} class JsonError extends Data.TaggedError("JsonError")<{}> {} const config = Config.string("BASE_URL"); const fetchRequest = (baseUrl: string) => Effect.tryPromise({ try: () => fetch(`${baseUrl}/api/v2/pokemon/garchomp/`), catch: () => new FetchError(), }); const jsonResponse = (response: Response) => Effect.tryPromise({ try: () => response.json(), catch: () => new JsonError(), }); const decodePokemon = Schema.decodeUnknown(Pokemon); const program = Effect.gen(function* () { const baseUrl = yield* config; const response = yield* fetchRequest(baseUrl); if (!response.ok) { return yield* new FetchError(); } const json = yield* jsonResponse(response); return yield* decodePokemon(json); }); const main = program.pipe( Effect.catchTags({ FetchError: () => Effect.succeed("Fetch error"), JsonError: () => Effect.succeed("Json error"), ParseError: () => Effect.succeed("Parse error"), }) ); Effect.runPromise(main).then(console.log);
TIP

代码组织的重要性

我们希望更好地组织我们的代码,使其更易于维护和测试。这就是 Effect 的真正力量:可组合性

我们通过创建所谓的服务来实现这一点。

重构:使代码更简洁#

NOTE

重构策略

在转向服务之前,重构代码是一个好主意(这将有助于稍后理解服务):

  • 我们可以将多个独立的函数收集到 .gen 内部,而不是拥有多个独立的函数

  • program 重命名为 getPokemon

const getPokemon = Effect.gen(function* () { const baseUrl = yield* Config.string("BASE_URL"); const response = yield* Effect.tryPromise({ try: () => fetch(`${baseUrl}/api/v2/pokemon/garchomp/`), catch: () => new FetchError(), }); if (!response.ok) { return yield* new FetchError(); } const json = yield* Effect.tryPromise({ try: () => response.json(), catch: () => new JsonError(), }); return yield* Schema.decodeUnknown(Pokemon)(json); });
IMPORTANT

代码模块化

现在很清楚,这个单一的 Effect 不是我们的完整程序,而只是我们代码库中的一个 API。

让我们也将错误和 Schema 移动到它们自己的独立文件中:

errors.ts

import { Data } from "effect"; export class FetchError extends Data.TaggedError("FetchError")<{}> {} export class JsonError extends Data.TaggedError("JsonError")<{}> {}

schemas.ts

import { Schema } from "effect"; export class Pokemon extends Schema.Class<Pokemon>("Pokemon")({ id: Schema.Number, order: Schema.Number, name: Schema.String, height: Schema.Number, weight: Schema.Number, }) {}

我们现在将在服务内部组织 Pokémon API。

[Effect Services] 01. 重构Effect代码
https://0bipinnata0.my/posts/course/effect-beginners-complete-getting-started/effect-services/01-refactoring-effect-code/
Author
0bipinnata0
Published at
2025-08-30 17:35:57