{"id":20444869,"url":"https://github.com/snapchat/ts-inject","last_synced_at":"2026-03-11T02:20:08.091Z","repository":{"id":253180428,"uuid":"834309923","full_name":"Snapchat/ts-inject","owner":"Snapchat","description":"Typesafe dependency injection framework for TypeScript projects, providing easy-to-use, maintainable, and scalable code with strong type safety.","archived":false,"fork":false,"pushed_at":"2026-03-05T08:56:19.000Z","size":323,"stargazers_count":19,"open_issues_count":4,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-03-05T10:42:43.847Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://snapchat.github.io/ts-inject/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Snapchat.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-07-26T22:55:54.000Z","updated_at":"2025-11-29T05:22:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"37220dd3-302c-4420-a3ec-b6c413acdc3d","html_url":"https://github.com/Snapchat/ts-inject","commit_stats":null,"previous_names":["snapchat/ts-inject"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/Snapchat/ts-inject","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snapchat%2Fts-inject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snapchat%2Fts-inject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snapchat%2Fts-inject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snapchat%2Fts-inject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Snapchat","download_url":"https://codeload.github.com/Snapchat/ts-inject/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snapchat%2Fts-inject/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30367811,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T21:41:54.280Z","status":"online","status_checked_at":"2026-03-11T02:00:07.027Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-15T10:09:29.760Z","updated_at":"2026-03-11T02:20:08.068Z","avatar_url":"https://github.com/Snapchat.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-inject\n\n`ts-inject` is a 100% typesafe dependency injection framework for TypeScript projects, designed to enhance code sharing and modularity by ensuring compile-time dependency resolution. This framework leverages the dependency injection design pattern to decouple dependency usage from creation, allowing components to rely on interfaces rather than implementations.\n\n## Features and Alternatives\n\n`ts-inject` brings typesafety to dependency injection, setting it apart from a vast majority of frameworks, like [InversifyJS](https://github.com/inversify/InversifyJS), which operate at runtime and therefore lack this level of typesafety.\n\nWhile [typed-inject](https://github.com/nicojs/typed-inject) also prioritizes typesafety, it lacks several key features that `ts-inject` offers:\n\n- **Overcomes TypeScript Nested Type Limitations**: Unlike some frameworks, `ts-inject` navigates around [TypeScript's limits on nested types](https://github.com/nicojs/typed-inject/issues/22), making it more robust for complex applications.\n- **Composable Containers**: `ts-inject` enables merging multiple containers, facilitating greater modularity and code reuse.\n- **PartialContainer**: It allows service registration without pre-defined dependencies, offering more flexibility compared to regular containers.\n\n## Getting Started\n\n### Installation\n\n```bash\nnpm install @snap/ts-inject\n```\n\n### Sample Usage\n\nThis quick start guide demonstrates how to define services, register them in a container, and then retrieve them for use.\n\n#### Defining Services\n\nDefine a couple of services. For simplicity, we'll use a `Logger` service and a `Database` service, where `Database` depends on `Logger` for logging purposes.\n\n```ts\nclass Logger {\n  log(message: string) {\n    console.log(`Log: ${message}`);\n  }\n}\n\nclass Database {\n  static dependencies = [\"Logger\"] as const;\n  constructor(private logger: Logger) {}\n\n  save(record: string) {\n    this.logger.log(`Saving record: ${record}`);\n  }\n}\n```\n\n#### Setting Up the Container\n\nWith `ts-inject`, you can set up a container to manage these services using `providesValue` and `providesClass`:\n\n```ts\nimport { Container } from \"@snap/ts-inject\";\n\nconst container = Container.providesValue(\"Logger\", new Logger()).providesClass(\"Database\", Database);\n\nconst db = container.get(\"Database\");\ndb.save(\"user1\"); // Log: Saving record: user1\n```\n\n#### Inline Factory Functions\n\nWhen a service needs custom creation logic, pass a factory function directly to `provides`:\n\n```ts\nimport { Container } from \"@snap/ts-inject\";\n\n// Zero-dependency lazy factory\nconst container = Container.provides(\"Logger\", () =\u003e new Logger());\n\n// Factory with dependencies — tokens are resolved from the container\nconst appContainer = container\n  .providesValue(\"apiUrl\", \"https://api.example.com\")\n  .provides(\"httpClient\", [\"apiUrl\"] as const, (url: string) =\u003e createHttpClient(url));\n```\n\nFor most services, prefer `providesValue` (eager values), `providesClass` (classes with `static dependencies`), or the inline `provides` form above. The `Injectable()` helper is only needed when you need a reusable factory object — for example, to pass to `run()` for eager initialization.\n\n#### Composable Containers\n\n`ts-inject` supports composable containers, allowing you to modularize service registration:\n\n```ts\nconst baseContainer = Container.providesValue(\"Logger\", new Logger());\nconst appContainer = baseContainer.providesClass(\"Database\", Database);\n\nconst db = appContainer.get(\"Database\");\ndb.save(\"user2\"); // Log: Saving record: user2\n```\n\nYou can also bootstrap a container from a plain object with `fromObject`:\n\n```ts\nconst configContainer = Container.fromObject({ apiUrl: \"https://api.example.com\", timeout: 5000 });\n```\n\n#### Multi-Binding\n\nContainers support appending to array-typed services, useful for plugin systems and extensible pipelines:\n\n```ts\nconst container = Container.providesValue(\"plugins\", [] as Plugin[])\n  .appendClass(\"plugins\", AuthPlugin)\n  .appendClass(\"plugins\", LoggingPlugin)\n  .appendValue(\"plugins\", { name: \"inline\", run: () =\u003e {} });\n\ncontainer.get(\"plugins\"); // [AuthPlugin, LoggingPlugin, { name: \"inline\", ... }]\n```\n\n### Key Concepts\n\n- **Container**: A registry for all services, handling their creation and retrieval.\n- **PartialContainer**: Similar to a Container but allows services to be registered without defining all dependencies upfront. Unlike a regular Container, it does not support retrieving services directly.\n- **Service**: Any value or instance provided by the Container.\n- **Token**: A unique identifier for each service, used for registration and retrieval within the Container.\n- **InjectableClass**: Classes that can be instantiated by the Container. Dependencies are specified in a static `dependencies` field to enable automatic injection via `providesClass`.\n- **InjectableFunction**: A reusable factory object created by `Injectable()`. Rarely needed directly — prefer the inline `provides('token', factory)` form. Use `Injectable()` when you need to store or pass a factory to `run()`.\n\n### API Reference\n\nFor comprehensive documentation of all ts-inject features and APIs, please refer to the [API Reference](https://snapchat.github.io/ts-inject/).\n\n## Contributing\n\n[Contributing guide](CONTRIBUTING.md).\n\n## License\n\n`ts-inject` is published under [MIT license](LICENSE.md).\n\n## Project Origins\n\n`ts-inject` originated as an internal project at [Snap Inc.](https://snap.com/), developed by [Weston Fribley](https://github.com/wfribley). Inspired by the principles of [typed-inject](https://github.com/nicojs/typed-inject), it was designed to address the limitations of existing dependency injection frameworks and improve typesafe dependency resolution in TypeScript. Initially aimed at enhancing [CameraKit](https://www.npmjs.com/package/@snap/camera-kit)'s codebase, its success led to its adoption across various teams at [Snap Inc.](https://snap.com/), and now it has evolved into an open-source project to benefit the wider TypeScript community.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapchat%2Fts-inject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnapchat%2Fts-inject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnapchat%2Fts-inject/lists"}