437 words
2 minutes
[Effect Layers] 03. 从实现推断服务类型
2025-08-30 18:20:10
2025-12-24 23:45:46

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

你现在可能会注意到 getPokemon 的类型错误:

Type 'BuildPokeApiUrl | PokemonCollection' is not assignable to type 'never'.

这是因为我们手动定义了 PokeApiImpl 接口,它不再符合新的实现(不期望依赖关系):

WARNING

依赖类型错误

每当你看到形如 Type 'Service' is not assignable to type 'never' 的类型问题时,它可能与缺失/过时的依赖关系有关(在这个例子中是 BuildPokeApiUrlPokemonCollection

PokeApi.ts

interface PokeApiImpl {
  /// `getPokemon` 的依赖关系是 `never`
  /// (`never` 是未定义时的默认类型)
  /// 
  /// 但我们的实现使用了 `BuildPokeApiUrl` 和 `PokemonCollection`
  /// ⛔️ 不能赋值给 `never`!
  readonly getPokemon: Effect.Effect<
    Pokemon,
    FetchError | JsonError | ParseResult.ParseError | ConfigError
  >;
}

export class PokeApi extends Context.Tag("PokeApi")<PokeApi, PokeApiImpl>() {

保持实现和类型同步是一件痛苦的事情,我们不想这样做。从实际实现中推导类型更快。

好消息!我们可以使用TypeScript的 typeof 来做到这一点。

我们首先定义一个包含服务实现的 make 值,并在创建 Context 服务时提供其类型定义:

PokeApi.ts

const make = {
  getPokemon: Effect.gen(function* () {
    const pokemonCollection = yield* PokemonCollection;
    const buildPokeApiUrl = yield* BuildPokeApiUrl;

    const requestUrl = buildPokeApiUrl({ name: pokemonCollection[0] });

    const response = yield* Effect.tryPromise({
      try: () => fetch(requestUrl),
      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);
  }),
};

export class PokeApi extends Context.Tag("PokeApi")<PokeApi, typeof make>() {
  static readonly Live = PokeApi.of(make);
}

现在服务类型是实现驱动的:我们可以专注于实现(当语言支持类型推断时,永远不必手动输入类型)。

TIP

推荐模式

这种 make+typeof 模式在Effect中是常见且推荐的

NOTE

由于我们更改了服务类型,我们还需要更新 Test 实现。

我们将在即将到来的课程中修复测试 🔜

[Effect Layers] 03. 从实现推断服务类型
https://0bipinnata0.my/posts/course/effect-beginners-complete-getting-started/layers/03-infer-service-type-from-implementation/
Author
0bipinnata0
Published at
2025-08-30 18:20:10