Skip to content

refactor(tsyringe): remove dependency - #1

Open
jeremycare wants to merge 5 commits into
mainfrom
refactor/remove-tsyringe
Open

jeremycare wants to merge 5 commits into
mainfrom
refactor/remove-tsyringe

Conversation

@jeremycare

Copy link
Copy Markdown
Contributor

Replace tsyringe with a Map-based registry

Summary

The container only used a small, non-decorator slice of tsyringe: isRegistered, register, resolve, reset, plus Lifecycle.Singleton and instanceCachingFactory. All of that reduces to "look up by token, instantiate once, cache". This PR replaces it with a single Map keyed on the Token instance itself, and drops both runtime dependencies.

The package now has zero runtime dependencies.

What changed

  • New container.ts: a module-level Map<Token, Entry> with has, set, resolve, and clear. Every provider kind (useValue, useClass, useFactory) resolves lazily on first inject and is cached afterwards, matching the previous singleton and caching-factory behavior.
  • Token.ts: no longer allocates a Symbol. The token object is the registry key, so identity and uniqueness come from the instance. A name field replaces the symbol description for error messages, and a phantom __type field keeps Token<A> and Token<B> non-interchangeable at the type level.
  • register.ts, inject.ts, reset.ts: thin wrappers over the new module. Public signatures and JSDoc are unchanged.
  • index.ts: removes the reflect-metadata side-effect import.
  • package.json: removes tsyringe and reflect-metadata, drops the tsyringe keyword, updates the description.
  • tsconfig.json: removes experimentalDecorators and emitDecoratorMetadata, which nothing used.
  • README.md: no longer describes the package as a Tsyringe wrapper.
  • di-container.test.ts: adds coverage for the behavior previously delegated to tsyringe (see Testing).

Why

  • The ClassProvider type is new () => T, so constructor injection was never possible through this API. The README already recommends inject() as a property initializer instead of constructors. Decorator metadata and reflect-metadata were dead weight.
  • Removing tsyringe removes a transitive install for every consumer and the reflect-metadata global polyfill side effect.

Breaking changes

  • Token.symbol is removed. Use Token.name for a readable label.
  • The package no longer imports reflect-metadata. Consumers who relied on this package to polyfill Reflect.metadata for their own decorators must import it themselves.
  • The error message for resolving an unregistered token now reads Attempted to resolve unregistered token <name>. instead of tsyringe's wording.

This warrants a major version bump.

Testing

  • tsc --noEmit: no errors
  • jest: 15 passed, 0 failed (8 existing, 7 new)
  • New tests cover:
    • useClass and useFactory providers resolve exactly once and return the same instance
    • class providers are instantiated lazily on first inject
    • default providers register on first inject and yield to explicit registrations
    • tokens with identical names are distinct registrations
    • Token<A> is not assignable to Token<B>, enforced via @ts-expect-error under ts-jest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant