{"id":12200,"library":"tsyringe","title":"TSyringe Dependency Injection Container","description":"TSyringe is a lightweight dependency injection (DI) container for JavaScript and TypeScript, primarily focusing on constructor injection. Currently at stable version 4.10.0, it is actively maintained and backed by Microsoft. Its release cadence appears to be feature-driven, with recent updates (v4.4.0) adding interception and transformation capabilities. Key differentiators include its strong integration with TypeScript decorators (`@injectable`, `@singleton`, `@inject`), its ability to handle complex dependency graphs including circular dependencies with a `delay` helper, and its provision for both class-based and interface-based injection using tokens. It requires `reflect-metadata` for decorator-based type reflection and specific `tsconfig.json` settings.","status":"active","version":"4.10.0","language":"javascript","source_language":"en","source_url":"https://github.com/Microsoft/tsyringe","tags":["javascript","dependency injection","dependency","injection","ioc","container","typescript"],"install":[{"cmd":"npm install tsyringe","lang":"bash","label":"npm"},{"cmd":"yarn add tsyringe","lang":"bash","label":"yarn"},{"cmd":"pnpm add tsyringe","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required runtime polyfill for decorator-based type reflection, must be imported once.","package":"reflect-metadata","optional":false}],"imports":[{"note":"Class decorator for enabling dependency injection.","wrong":"const { injectable } = require('tsyringe');","symbol":"injectable","correct":"import { injectable } from 'tsyringe';"},{"note":"The global container instance for registering and resolving dependencies.","wrong":"import Container from 'tsyringe';","symbol":"container","correct":"import { container } from 'tsyringe';"},{"note":"Class decorator to register a class as a singleton.","wrong":"import { Singleton } from 'tsyringe';","symbol":"singleton","correct":"import { singleton } from 'tsyringe';"},{"note":"Parameter decorator used for injecting dependencies by token, especially useful for interfaces or primitive values.","wrong":"import { Inject } from 'tsyringe';","symbol":"inject","correct":"import { inject } from 'tsyringe';"}],"quickstart":{"code":"import \"reflect-metadata\"; // Must be imported ONCE at the very top of your application entry point\nimport { container, injectable, inject, singleton } from \"tsyringe\";\n\n// 1. Define an interface for abstraction\ninterface IDatabaseService {\n  connect(): void;\n  getData(query: string): string;\n}\n\n// 2. Implement the interface and mark as injectable\n@injectable()\nclass RealDatabaseService implements IDatabaseService {\n  connect() {\n    console.log(\"Connected to a real database.\");\n  }\n  getData(query: string): string {\n    return `Data for: ${query} from RealDatabase`;\n  }\n}\n\n// 3. Define a service that depends on IDatabaseService\n@injectable()\nclass DataProcessorService {\n  constructor(@inject(\"IDatabaseService\") private dbService: IDatabaseService) {\n    this.dbService.connect();\n  }\n\n  processUserData(userId: string): string {\n    const query = `SELECT * FROM users WHERE id = ${userId}`;\n    return `Processing user data: ${this.dbService.getData(query)}`;\n  }\n}\n\n// 4. Register the interface with its implementation in the container\ncontainer.register<IDatabaseService>(\"IDatabaseService\", {\n  useClass: RealDatabaseService,\n});\n\n// 5. Resolve the DataProcessorService\nconst dataProcessor = container.resolve(DataProcessorService);\nconsole.log(dataProcessor.processUserData(\"123\"));\n\n// 6. Example of a singleton service\n@singleton()\nclass AppConfig {\n  public readonly API_KEY = process.env.API_KEY ?? 'default-api-key';\n  constructor() {\n    console.log(\"AppConfig initialized (should only happen once for singleton).\");\n  }\n}\n\nconst config1 = container.resolve(AppConfig);\nconst config2 = container.resolve(AppConfig);\nconsole.log(`API Key: ${config1.API_KEY}`);\nconsole.log(`Are config instances identical? ${config1 === config2}`);\n\n/*\n  NOTE: Ensure your tsconfig.json includes:\n  {\n    \"compilerOptions\": {\n      \"experimentalDecorators\": true,\n      \"emitDecoratorMetadata\": true\n    }\n  }\n*/\n","lang":"typescript","description":"Demonstrates basic setup, interface-based dependency injection, and singleton registration."},"warnings":[{"fix":"Add or ensure the following in your `tsconfig.json`: `\"compilerOptions\": { \"experimentalDecorators\": true, \"emitDecoratorMetadata\": true }`","message":"TSyringe heavily relies on TypeScript's decorator metadata. You must enable `experimentalDecorators` and `emitDecoratorMetadata` in your `tsconfig.json` under `compilerOptions`.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Install `reflect-metadata` (`npm install reflect-metadata`) and add `import \"reflect-metadata\";` as the very first line in your main application file (e.g., `main.ts` or `index.ts`).","message":"A polyfill for the Reflect API (e.g., `reflect-metadata`) is a mandatory runtime dependency. It must be imported exactly once in your application's entry point, *before* any TSyringe code or decorated classes are loaded.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Install `babel-plugin-transform-typescript-metadata` (`npm install --save-dev babel-plugin-transform-typescript-metadata`) and add it to your Babel configuration's `plugins` array.","message":"If you are using Babel (e.g., in a React Native project), you must install and configure `babel-plugin-transform-typescript-metadata` to ensure TypeScript metadata is correctly emitted.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Wrap the dependency registration or injection with `delay(() => DependencyClass)` or `delay(() => container.resolve(DependencyClass))`.","message":"Handling circular dependencies requires using the `delay` helper function when registering or injecting. Without it, you will encounter runtime errors or `undefined` dependencies.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Ensure that all classes intended for injection are decorated with `@injectable()` and that any interfaces or custom tokens have a corresponding `container.register()` call.","cause":"A class or interface token was requested from the container but was never registered, or the `@injectable()` decorator was omitted from a class intended for injection.","error":"No matching binding found for token: [object Object]"},{"fix":"Verify `reflect-metadata` is installed (`npm install reflect-metadata`) and that `import \"reflect-metadata\";` is the absolute first line in your application's entry point.","cause":"The `reflect-metadata` polyfill was either not imported, imported incorrectly, or imported after TSyringe or decorated classes were loaded.","error":"TypeError: Reflect.metadata is not a function"},{"fix":"Check your `tsconfig.json` for `\"experimentalDecorators\": true` and `\"emitDecoratorMetadata\": true`. If using Babel, ensure `babel-plugin-transform-typescript-metadata` is installed and configured in your Babel plugins.","cause":"The TypeScript compiler options `experimentalDecorators` or `emitDecoratorMetadata` are not correctly set in `tsconfig.json`, or Babel is not configured for metadata emission.","error":"SyntaxError: Decorators are not enabled."}],"ecosystem":"npm"}