471 words
2 minutes
[Effect Layers] 06. 多次提供同一层
2025-08-30 18:20:13
2025-12-24 23:45:46

多次提供同一层#

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

你可能注意到了一些奇怪的事情:我们在组合 MainLayer 时使用了两次 PokeApiUrlLive

const MainLayer = Layer.mergeAll(
  PokeApi.Live,
  PokemonCollection.Live,
  BuildPokeApiUrl.Live.pipe(Layer.provide(PokeApiUrl.Live)),
  PokeApiUrl.Live,
);

这是一个问题吗?层会被创建多次吗?

TIP

层的记忆化

这完全不是问题,因为Effect中的层是记忆化的。这意味着每个层只会被创建一次,每次都会提供相同的实例。

这使得组合层变得更加方便。

实际上,Live 内定义 Layer 时直接提供所需的依赖关系是一个好的实践:

BuildPokeApiUrl.ts

export class BuildPokeApiUrl extends Context.Tag("BuildPokeApiUrl")<
  BuildPokeApiUrl,
  ({ name }: { name: string }) => string
>() {
  static readonly Live = Layer.effect(
    this,
    Effect.gen(function* () {
      const pokeApiUrl = yield* PokeApiUrl;
      return ({ name }) => `${pokeApiUrl}/${name}`;
    })
  ).pipe(
    // 在 `Live` 内直接提供依赖层
    Layer.provide(PokeApiUrl.Live)
  );
}

有了这些,MainLayer 只需要一个简单的 mergeAll 来包含运行程序所需的所有层:

index.ts

const MainLayer = Layer.mergeAll(
  PokeApi.Live,
  PokemonCollection.Live,
  BuildPokeApiUrl.Live,
  PokeApiUrl.Live
);
IMPORTANT

Effect 组合模型的强大之处

这就是Effect组合模型的全部力量!我们可以通过更改一行代码来交换层。这允许轻松地混合和组合不同的实现,同时保持完全的类型安全

此外,我们可以再次专注于单个服务实现,而不必担心其依赖关系或错误。

NOTE

开发体验优势

一切都在最后收集和提供。对代码库进行更改变得更容易,因为我们不需要阅读或理解所有内容,而是可以专注于单个服务。

维护应用程序也变得更容易,因为每个破坏性更改都会导致类型问题,TypeScript编译器会指导我们在需要的地方解决

这就是完全的类型安全!这是不归路:一旦你理解了这个模型有多强大,你就再也不会回头了!

[Effect Layers] 06. 多次提供同一层
https://0bipinnata0.my/posts/course/effect-beginners-complete-getting-started/layers/06-providing-the-same-layer-more-than-once/
Author
0bipinnata0
Published at
2025-08-30 18:20:13