Clarification on the Use of `Id` vs `Self` in `Context.Tag`

export const Tag: <const Id extends string>(id: Id) => <Self, Shape>() => TagClass<Self, Id, Shape> = internal.Tag

Could someone explain the relationship between Id and Self for Context.Tag please?

From my understanding, the Id is used as the key to resolve the value/implementation of Shape from the Context

Why is Self ie. the class that extends Context.Tag (S1 or S2 in the screenshot) not used as the key instead?

Assuming Context is some kind of JS Map under the hood, anything could be used as the key including the class itself ie.
const Context = new Map()
Context.set(S1, "a") // ie. Effect.provideService(S1, "a")
Context.set(S2, 1)   // ie. Effect.provideService(S2, 1)

This would circumvent the need for unique string identifiers and the issue shown in the screenshot where duplicate IDs ("S1" in the example) for different services (eg. S1 and S2) with different interfaces/shapes resolve to whichever implementation is provided first to the Context
Screenshot_2025-09-22_at_20.38.54.png
Was this page helpful?