{"id":28618898,"url":"https://github.com/alexsergey/friendly-di","last_synced_at":"2025-07-23T09:05:36.725Z","repository":{"id":261263414,"uuid":"882049486","full_name":"AlexSergey/friendly-di","owner":"AlexSergey","description":"A lightweight and high-performance inversion of control (IoC) container inspired by NestJS and Angular.","archived":false,"fork":false,"pushed_at":"2024-11-28T18:02:48.000Z","size":267,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-12T04:19:01.584Z","etag":null,"topics":["dependency-injection","inversion-of-control","oop","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AlexSergey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2024-11-01T19:16:12.000Z","updated_at":"2025-02-11T00:29:14.000Z","dependencies_parsed_at":"2025-03-18T01:07:31.306Z","dependency_job_id":"b0e691b9-d91f-4cd2-8d5a-2246034af904","html_url":"https://github.com/AlexSergey/friendly-di","commit_stats":null,"previous_names":["alexsergey/friendly-di"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/AlexSergey/friendly-di","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexSergey%2Ffriendly-di","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexSergey%2Ffriendly-di/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexSergey%2Ffriendly-di/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexSergey%2Ffriendly-di/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlexSergey","download_url":"https://codeload.github.com/AlexSergey/friendly-di/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexSergey%2Ffriendly-di/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265336126,"owners_count":23749170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dependency-injection","inversion-of-control","oop","typescript"],"created_at":"2025-06-12T04:18:48.689Z","updated_at":"2025-07-23T09:05:36.716Z","avatar_url":"https://github.com/AlexSergey.png","language":"TypeScript","readme":"\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Friendly DI\" src=\"https://www.natrube.net/friendly-di/friendly-di.png\"\u003e\n\u003c/p\u003e\n\n[![Version](https://img.shields.io/npm/v/friendly-di.svg?color=rgb(237,18,182)\u0026labelColor=26272b)](https://www.npmjs.com/package/friendly-di)\n[![GitHub License](https://img.shields.io/badge/license-MIT-232428.svg?color=rgb(237,18,182)\u0026labelColor=26272b)](https://www.npmjs.com/package/friendly-di)\n\n**Friendly DI** is light and fast Inversion Of Control Container based on Reflect metadata inspired by Angular and Nest DI systems.\n\n**Friendly DI** is very versatile tool. You can use it in Node.js projects (express, koa, whatever), in the Browser (pure JS projects, React projects etc.).\n\n**Benefits:**\n\n- **Small size**: Just 2 KB with no external dependencies.\n- **Cross-platform**: Works seamlessly in both the browser and Node.js environments.\n- **Simple API**: Intuitive and easy to use, with minimal configuration.\n- **MIT License**: Open-source with permissive licensing.\n\n***\n\n## How it works\n\nIoC Container pattern helps to solve the problem of tightly coupled dependencies. The idea behind this approach\nis that a class does not depend on another class directly, but depends on an interface. Thus, if there is a need to\nreplace one of the dependencies, it is enough for the declare dependency with the same interfaces into the IoC Container.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"IoC Diagram\" src=\"https://www.natrube.net/friendly-di/ioc-diagram.png\"\u003e\n\u003c/p\u003e\n\n- Classes are linked via interfaces\n- IoC Container registers dependencies\n- When a class is extracted from a container, it will have all declared or substituted dependencies\n\nIf you wanna deep dive into Dependency Injection vs Dependency Inversion principle vs Inversion Of Control etc please\nreach the link with article:\n\n[Mastering the Dependency Inversion Principle: Best Practices for Clean Code with DI](https://dev.to/alexsergey/mastering-the-dependency-inversion-principle-best-practices-for-clean-code-with-di-5c0k)\n\n## Usage\n\n**Friendly DI** based the same idea as Angular DI has and NestJS DI has. We used interfaces in the constructor and Container establish connection from real instances and interfaces via metadata.\n\n**Friendly DI** has Typescript metadata support. It's not possible to run it without Typescript.\n\n1. Installation:\n\n```shell\nnpm i friendly-di reflect-metadata\n```\n\n2. Add 2 lines in *tsconfig.json*:\n\n```json\n{\n  \"compilerOptions\": {\n    \"experimentalDecorators\": true,\n    \"emitDecoratorMetadata\": true\n  }\n}\n\n```\n\n3. Add Injectable decorator to each class and declare dependencies in constructor:\n\n*! Important:*\n\nIt is recommended to containerize the root of your application to comply with the [composition root](https://blog.ploeh.dk/2011/07/28/CompositionRoot/)\nto avoid the [service locator](https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/) anti-pattern.\nIn this example *class App* is our composition root.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg alt=\"Friendly DI Diagram\" src=\"https://www.natrube.net/friendly-di/4.png\"\u003e\n\u003c/p\u003e\n\n```ts\nimport 'reflect-metadata';\nimport { Injectable, Container } from 'friendly-di';\n\n@Injectable()\nclass ProductService {\n  getProducts() {\n    return ['product 1', 'product 2', 'product 3'];\n  }\n}\n\n@Injectable()\nclass OrderService {\n  constructor(private productService: ProductService) {\n  }\n\n  getOrdersForUser() {\n    return this.productService.getProducts();\n  }\n}\n\n@Injectable()\nclass UserService {\n  constructor(private orderService: OrderService) {\n  }\n\n  getUserOrders() {\n    return this.orderService.getOrdersForUser();\n  }\n}\n\n\n@Injectable()\nclass App {\n  constructor(private userService: UserService) {\n  }\n\n  run() {\n    return this.userService.getUserOrders();\n  }\n}\n```\n\n4. Declare container and root class:\n\n```ts\nconst app = new Container(App).compile();\n\napp.run() // 'product 1', 'product 2', 'product 3'\n```\n\n## Use Cases\n\nIf we need to mock nested dependencies we should:\n\n1. Make mock-class with similar interface:\n\n```ts\n@Injectable()\nclass MockProductService {\n  getProducts() {\n    return ['new product 1', 'new product 2', 'new product 3'];\n  }\n}\n```\n\n2. When we declare container with root we also can replace classes:\n\n```ts\nconst app = new Container(App)\n  .replace(ProductService, MockProductService)\n  .compile();\n\napp.run() // 'new product 1', 'new product 2', 'new product 3'\n```\n\n*replace* method receives 2 arguments: Replaceable class, Class to be replaced.\n\nMethod *replace* is chainable, so we can make replace many times:\n\n```ts\nconst app = new Container(App)\n  .replace(ProductService, MockProductService)\n  .replace(OrderService, MockOrderService)\n  .compile();\n\napp.run() // 'new product 1', 'new product 2', 'new product 3'\n```\n\n## Limitations\n\n### TSX issue\n\nCurrently, **friendly-di** has problems with [tsx](https://github.com/privatenumber/tsx) usage. If you need use **friendly-di** in Node.js project please use *ts-node/esm* loader:\n\n```shell\nnode --loader ts-node/esm index.ts\n```\n\n### Interfaces Dependency\n\n**friendly-di** does not support interface as a dependency. Please use classes:\n\n*Wrong*\n\n```ts\ninterface ProductServiceInterface {\n  getProducts(): string[];\n}\n@Injectable()\nclass OrderService {\n  constructor(private productService: ProductServiceInterface) {\n  }\n\n  getOrdersForUser() {\n    return this.productService.getProducts();\n  }\n}\n```\n\n*Correct*\n\n```ts\n@Injectable()\nclass ProductService {\n  getProducts() {\n    return ['product 1', 'product 2', 'product 3'];\n  }\n}\n\n@Injectable()\nclass OrderService {\n  constructor(private productService: ProductService) {\n  }\n\n  getOrdersForUser() {\n    return this.productService.getProducts();\n  }\n}\n```\n\n## Alternatives\n\nIf you use projects like Angular, NestJS... I congratulate you! You don't need **friendly-di**, as there is already a great and very similar DI system there.\n\n[Inversify](https://github.com/inversify/InversifyJS/tree/master) - The most popular IoC Container library in JS. The\ndownside is that you'll have to write a lot of boilerplate code. It has a large number of features that may be specific\nto large projects.\n\n## The MIT License\n\nCopyright (c) Sergey Aleksandrov\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\ndocumentation files (the “Software”), to deal in the Software without restriction, including without limitation the\nrights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the following conditions:\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexsergey%2Ffriendly-di","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexsergey%2Ffriendly-di","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexsergey%2Ffriendly-di/lists"}