{"id":13912520,"url":"https://github.com/nicojs/typed-inject","last_synced_at":"2025-05-14T11:11:43.737Z","repository":{"id":34671106,"uuid":"167599152","full_name":"nicojs/typed-inject","owner":"nicojs","description":"Type safe dependency injection for TypeScript","archived":false,"fork":false,"pushed_at":"2024-12-13T22:05:09.000Z","size":455,"stargazers_count":503,"open_issues_count":13,"forks_count":22,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-12T22:18:31.544Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nicojs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2019-01-25T19:07:14.000Z","updated_at":"2025-05-06T09:57:57.000Z","dependencies_parsed_at":"2024-06-18T13:36:20.295Z","dependency_job_id":"22c5d851-ec8c-40ae-beda-f417639610c0","html_url":"https://github.com/nicojs/typed-inject","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-inject","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-inject/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-inject/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nicojs%2Ftyped-inject/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nicojs","download_url":"https://codeload.github.com/nicojs/typed-inject/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254129523,"owners_count":22019628,"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":[],"created_at":"2024-08-07T01:01:31.389Z","updated_at":"2025-05-14T11:11:38.716Z","avatar_url":"https://github.com/nicojs.png","language":"TypeScript","funding_links":[],"categories":["others","**1. Libraries**"],"sub_categories":["Others"],"readme":"[![Mutation testing badge](https://img.shields.io/endpoint?style=flat\u0026url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fnicojs%2Ftyped-inject%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/nicojs/typed-inject/master)\n[![Build Status](https://travis-ci.org/nicojs/typed-inject.svg?branch=master)](https://travis-ci.org/nicojs/typed-inject)\n[![NPM](https://img.shields.io/npm/dm/typed-inject.svg)](https://www.npmjs.com/package/typed-inject)\n[![Node version](https://img.shields.io/node/v/typed-inject.svg)](https://img.shields.io/node/v/stryker-utils.svg)\n[![Gitter](https://badges.gitter.im/stryker-mutator/stryker.svg)](https://gitter.im/stryker-mutator/stryker?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\n# Typed Inject\n\n\u003e Typesafe dependency injection for TypeScript\n\nA tiny, 100% typesafe dependency injection framework for TypeScript. You can inject classes, interfaces, or primitives. If your project compiles, you know your dependencies are resolved at runtime and have their declared types.\n\n_If you are new to 'Dependency Injection'/'Inversion of control', please read up on it [in this blog article about it](https://medium.com/@samueleresca/inversion-of-control-and-dependency-injection-in-typescript-3040d568aabe)_\n\n_If you want to know more about how typed-inject works, please read [my blog article about it](https://medium.com/@jansennico/advanced-typescript-type-safe-dependency-injection-873426e2cc96)_\n\n- [🗺️ Installation](#installation)\n- [🎁 Usage](#usage)\n- [💭 Motivation](#motivation)\n- [🗝️ Typesafe? How?](#typesafe-how)\n- [👶 Child injectors](#child-injectors)\n- [🎄 Decorate your dependencies](#decorate-your-dependencies)\n- [♻ Lifecycle control](#lifecycle-control)\n- [🚮 Disposing provided stuff](#disposing-provided-stuff)\n- [✨ Magic tokens](#magic-tokens)\n- [😬 Error handling](#error-handling)\n- [📖 API reference](#api-reference)\n- [🤝 Commendation](#commendation)\n\n\u003ca name=\"installation\"\u003e\u003c/a\u003e\n\n## 🗺️ Installation\n\nInstall typed-inject locally within your project folder, like so:\n\n```shell\nnpm i typed-inject\n```\n\nOr with yarn:\n\n```shell\nyarn add typed-inject\n```\n\n_Note: this package uses advanced TypeScript features. Only TS 3.0 and above is supported!_\n\n_Note: due to a [bug in TypeScript \u003e3.8 \u003c4.5](https://github.com/microsoft/TypeScript/issues/37400) there is a small chance that the compiler [doesn't catch all errors](https://github.com/nicojs/typed-inject/issues/20) (as well as you might experience some performance issues)._\n\n_Note: projects must enable [`--strictFunctionTypes`](https://www.typescriptlang.org/tsconfig#strictFunctionTypes) (or `--strict`) in their Typescript config or some type errors may not be caught._\n\n\u003ca name=\"usage\"\u003e\u003c/a\u003e\n\n## 🎁 Usage\n\nAn example:\n\n```ts\nimport { createInjector } from 'typed-inject';\n\ninterface Logger {\n  info(message: string): void;\n}\n\nconst logger: Logger = {\n  info(message: string) {\n    console.log(message);\n  },\n};\n\nclass HttpClient {\n  constructor(private log: Logger) {}\n  public static inject = ['logger'] as const;\n}\n\nclass MyService {\n  constructor(\n    private http: HttpClient,\n    private log: Logger,\n  ) {}\n  public static inject = ['httpClient', 'logger'] as const;\n}\n\nconst appInjector = createInjector()\n  .provideValue('logger', logger)\n  .provideClass('httpClient', HttpClient);\n\nconst myService = appInjector.injectClass(MyService);\n// Dependencies for MyService validated and injected\n```\n\nIn this example:\n\n- The `logger` is injected into a new instance of `HttpClient` by value.\n- The instance of `HttpClient` and the `logger` are injected into a new instance of `MyService`.\n\nDependencies are resolved using the static `inject` property in their classes. They must match the names given to the dependencies when configuring the injector with `provideXXX` methods.\n\nExpect compiler errors when you mess up the order of tokens or forget it completely.\n\n```ts\nimport { createInjector } from 'typed-inject';\n\n// Same logger as before\n\nclass HttpClient {\n  constructor(private log: Logger) {}\n  // ERROR! Property 'inject' is missing in type 'typeof HttpClient' but required\n}\n\nclass MyService {\n  constructor(\n    private http: HttpClient,\n    private log: Logger,\n  ) {}\n  public static inject = ['logger', 'httpClient'] as const;\n  // ERROR! Types of parameters 'http' and 'args_0' are incompatible\n}\n\nconst appInjector = createInjector()\n  .provideValue('logger', logger)\n  .provideClass('httpClient', HttpClient);\n\nconst myService = appInjector.injectClass(MyService);\n```\n\nThe error messages are a bit cryptic at times, but it sure is better than running into them at runtime.\n\n\u003ca name=\"motivation\"\u003e\u003c/a\u003e\n\n## 💭 Motivation\n\nJavaScript and TypeScript development already has a great dependency injection solution with [InversifyJS](https://github.com/inversify/InversifyJS). However, InversifyJS comes with 2 caveats.\n\n### InversifyJS uses Reflect-metadata\n\nInversifyJS works with a nice API using decorators. Decorators are in Stage 2 of ecma script proposal at the moment of writing this, so they will most likely land in ESNext. However, it also is opinionated in that it requires you to use [reflect-metadata](https://rbuckton.github.io/reflect-metadata/), which [is supposed to be an ecma script proposal, but isn't yet (at the moment of writing this)](https://github.com/rbuckton/reflect-metadata/issues/96). It might take years for reflect-metadata to land in JavaScript, if it ever does.\n\n### InversifyJS is not typesafe\n\nInversifyJS is also _not_ typesafe. There is no check to see of the injected type is actually injectable or that the corresponding type adheres to the expected type.\n\n\u003ca name=\"typesafe-how\"\u003e\u003c/a\u003e\n\n## 🗝️ Typesafe? How?\n\nType safe dependency injection works by combining excellent TypeScript features. Some of those features are:\n\n- [Literal types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types)\n- [Intersection types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#intersection-types)\n- [Mapped types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#mapped-types)\n- [Conditional types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types)\n- [Rest parameters with tuple types](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#rest-parameters-with-tuple-types)\n\nPlease read [my blog article on Medium](https://medium.com/@jansennico/advanced-typescript-type-safe-dependency-injection-873426e2cc96) if you want to know how this works.\n\n\u003ca name=\"child-injectors\"\u003e\u003c/a\u003e\n\n## 👶 Child injectors\n\nThe `Injector` interface is responsible for injecting classes or functions. You start off with an empty injector after calling `createInjector`. It can't provide any dependencies directly (except for [magic tokens](#-magic-tokens)).\n\nTo do anything useful with your injector, you'll need to create child injectors. This what you do with the `provideXXX` methods.\n\n```ts\nimport { createInjector } from 'typed-inject';\nfunction barFactory(foo: number) {\n  return foo + 1;\n}\nbarFactory.inject = ['foo'] as const;\nclass Baz {\n  constructor(bar: number) {\n    console.log(`bar is: ${bar}`);\n  }\n  static inject = ['bar'] as const;\n}\n\n// Create 3 child injectors here\nconst childInjector = createInjector()\n  .provideValue('foo', 42) // child injector can provide 'foo'\n  .provideFactory('bar', barFactory) // child injector can provide both 'bar' and 'foo'\n  .provideClass('baz', Baz); // child injector can provide 'baz', 'bar' and 'foo'\n\n// Now use it here\nfunction run(baz: Baz) {\n  // baz is created!\n}\nrun.inject = ['baz'] as const;\nchildInjector.injectFunction(run);\n```\n\nIn the example above, a child injector is created. It can provide values for the tokens `'foo'`, `'bar'` and `'baz'`. You can create as many child injectors as you want.\n\nInjectors keep track of their child injectors and values they've injected. This way it can provide functionality like [cache the injected value](#-control-lifecycle) or [keep track of stuff to dispose](#-disposing-provided-stuff).\n\n\u003ca name=\"decorate-your-dependencies\"\u003e\u003c/a\u003e\n\n## 🎄 Decorate your dependencies\n\nA common use case for dependency injection is the [decorator design pattern](https://en.wikipedia.org/wiki/Decorator_pattern). It is used to dynamically add functionality to existing dependencies. Typed inject supports decoration of existing dependencies using its `provideFactory` and `provideClass` methods.\n\n```ts\nimport { createInjector } from 'typed-inject';\n\nclass Foo {\n  public bar() {\n    console.log('bar!');\n  }\n}\n\nfunction fooDecorator(foo: Foo) {\n  return {\n    bar() {\n      console.log('before call');\n      foo.bar();\n      console.log('after call');\n    },\n  };\n}\nfooDecorator.inject = ['foo'] as const;\n\nconst fooProvider = createInjector()\n  .provideClass('foo', Foo)\n  .provideFactory('foo', fooDecorator);\nconst foo = fooProvider.resolve('foo');\n\nfoo.bar();\n// =\u003e \"before call\"\n// =\u003e \"bar!\"\n// =\u003e \"after call\"\n```\n\nIn this example above the `Foo` class is decorated by the `fooDecorator`.\n\n\u003ca name=\"lifecycle-control\"\u003e\u003c/a\u003e\n\n## ♻ Lifecycle control\n\nYou can determine the lifecycle of dependencies with the third `Scope` parameter of `provideFactory` and `provideClass` methods.\n\n```ts\nfunction loggerFactory(target: Function | null) {\n  return getLogger((target \u0026\u0026 target.name) || 'UNKNOWN');\n}\nloggerFactory.inject = ['target'] as const;\n\nclass Foo {\n  constructor(public log: Logger) {\n    log.info('Foo created');\n  }\n  static inject = ['log'] as const;\n}\n\nconst fooProvider = injector\n  .provideFactory('log', loggerFactory, Scope.Transient)\n  .provideClass('foo', Foo, Scope.Singleton);\nconst foo = fooProvider.resolve('foo');\nconst fooCopy = fooProvider.resolve('foo');\nconst log = fooProvider.resolve('log');\nconsole.log(foo === fooCopy); // =\u003e true\nconsole.log(log === foo.log); // =\u003e false\n```\n\nA scope has 2 possible values.\n\n- `Scope.Singleton` (default value)  \n  Use `Scope.Singleton` to enable caching. Every time the dependency needs to be provided by the injector, the same instance is returned. Other injectors will still create their own instances, so it's only a `Singleton` for the specific injector (and child injectors created from it). In other words,\n  the instance will be _scoped to the `Injector`_\n- `Scope.Transient`  \n  Use `Scope.Transient` to altogether disable cashing. You'll always get fresh instances.\n\n\u003ca name=\"disposing-provided-stuff\"\u003e\u003c/a\u003e\n\n## 🚮 Disposing provided stuff\n\nMemory in JavaScript is garbage collected, so, we usually don't care about cleaning up after ourselves. However, there might be a need to explicit cleanup. For example removing a temp folder, or killing a child process.\n\nAs `typed-inject` is responsible for creating (providing) your dependencies, it only makes sense it is also responsible for the disposing of them.\n\nAny `Injector` has a `dispose` method. Calling it will call `dispose` on any instance that was ever provided from it, as well as any child injectors that were created from it.\n\n```ts\nimport { createInjector } from 'typed-inject';\n\nclass Foo {\n  constructor() {\n    console.log('Foo created');\n  }\n  dispose() {\n    console.log('Foo disposed');\n  }\n}\nconst rootInjector = createInjector();\nconst fooProvider = rootInjector.provideClass('foo', Foo);\nfooProvider.resolve('foo'); // =\u003e \"Foo created\"\nawait rootInjector.dispose(); // =\u003e \"Foo disposed\"\nfooProvider.resolve('foo'); // Error: Injector already disposed\n```\n\n_Note: Always dispose from the top down! In this example, the `rootInjector` is disposed, which in turn disposes everything that was ever provided from one if it's child injectors._\n\nTo help you implementing the `dispose` method correctly, `typed-inject` exports the `Disposable` interface for convenience:\n\n```ts\nimport { Disposable } from 'typed-inject';\nclass Foo implements Disposable {\n  dispose() {}\n}\n```\n\nDispose methods are typically `async`. For example, you might need to clean up some files or get rid of a child process.\nIf you do so, your dependencies should return a promise from the `dispose` method. In turn, calling `dispose` on an `Injector` is always async.\nYou are responsible for the correct handling of the async behavior of the `dispose` method.\nThis means you should either `await` the result or attach `then`/`catch` handlers.\n\n```ts\nimport { createInjector, Disposable } from 'typed-inject';\nclass Foo implements Disposable {\n  dispose(): Promise\u003cvoid\u003e {\n    return Promise.resolve();\n  }\n}\nconst rootInjector = createInjector();\nconst fooProvider = rootInjector\n  .provideClass('foo', Foo);\nconst foo = fooProvider.resolve('foo');\nasync function disposeFoo() {\n  await fooProvider.dispose();\n}\ndisposeFoo()\n  .then(() =\u003e console.log('Foo disposed'))\n  .catch(err =\u003e console.error('Foo disposal resulted in an error', err);\n```\n\nUsing `dispose` on the rootInjector will automatically dispose it's child injectors as well:\n\n```ts\nimport { createInjector } from 'typed-inject';\nclass Foo {}\nclass Bar {}\nconst rootInjector = createInjector();\nconst fooProvider = rootInjector.provideClass('foo', Foo);\nconst barProvider = fooProvider.provideClass('bar', Bar);\nawait rootInjector.dispose(); // =\u003e fooProvider is also disposed!\nfooProvider.resolve('foo'); // =\u003e Error: Injector already disposed\n```\n\nDisposing of provided values is done in order of child first. So they are disposed in the opposite order of respective `providedXXX` calls (like a stack):\n\n```ts\nimport { createInjector } from 'typed-inject';\n\nclass Foo {\n  dispose() {\n    console.log('Foo disposed');\n  }\n}\nclass Bar {\n  dispose() {\n    console.log('Bar disposed');\n  }\n}\nclass Baz {\n  static inject = ['foo', 'bar'] as const;\n  constructor(\n    public foo: Foo,\n    public bar: Bar,\n  ) {}\n}\nconst rootInjector = createInjector();\nrootInjector.provideClass('foo', Foo).provideClass('bar', Bar).injectClass(Baz);\nawait fooProvider.dispose();\n// =\u003e \"Foo disposed\"\n// =\u003e \"Bar disposed\",\n```\n\nAny instance created with `injectClass` or `injectFactory` will _not_ be disposed when `dispose` is called. You were responsible for creating it, so you are also responsible for the disposing of it. In the same vain, anything provided as a value with `providedValue` will also _not_ be disposed when `dispose` is called on it's injector.\n\n\u003ca name=\"magic-tokens\"\u003e\u003c/a\u003e\n\n## ✨ Magic tokens\n\nAny `Injector` instance can always provide the following tokens:\n\n| Token name       | Token value   | Description                                                                                         |\n| ---------------- | ------------- | --------------------------------------------------------------------------------------------------- |\n| `INJECTOR_TOKEN` | `'$injector'` | Injects the current injector                                                                        |\n| `TARGET_TOKEN`   | `'$target'`   | The class or function in which the current values are injected, or `undefined` if resolved directly |\n\nAn example:\n\n```ts\nimport {\n  createInjector,\n  Injector,\n  TARGET_TOKEN,\n  INJECTOR_TOKEN,\n} from 'typed-inject';\n\nclass Foo {\n  constructor(injector: Injector\u003c{}\u003e, target: Function | undefined) {}\n  static inject = [INJECTOR_TOKEN, TARGET_TOKEN] as const;\n}\n\nconst foo = createInjector().inject(Foo);\n```\n\n\u003ca name=\"error-handling\"\u003e\u003c/a\u003e\n\n## 😬 Error handling\n\nWhen a runtime error occurs, typed inject will provide you with the exact path where the error occurred.\n\n```ts\nclass GrandChild {\n  public baz = 'baz';\n  constructor() {\n    throw expectedCause;\n  }\n}\nclass Child {\n  public bar = 'foo';\n  constructor(public grandchild: GrandChild) {}\n  public static inject = ['grandChild'] as const;\n}\nclass Parent {\n  constructor(public readonly child: Child) {}\n  public static inject = ['child'] as const;\n}\ncreateInjector()\n  .provideClass('grandChild', GrandChild)\n  .provideClass('child', Child)\n  .injectClass(Parent);\n// =\u003e Error: Could not inject [class Parent] -\u003e [token \"child\"] -\u003e [class Child] -\u003e [token \"grandChild\"] -\u003e [class GrandChild]. Cause: Expected error\n```\n\nWhen you handle the error, you will be able to capture the original `cause`.\n\n```ts\nimport { InjectionError } from 'typed-inject';\ntry {\n  createInjector()\n    .provideClass('grandChild', GrandChild)\n    .provideClass('child', Child)\n    .injectClass(Parent);\n} catch (err) {\n  if (err instanceof InjectionError) {\n    console.error(err.cause.stack);\n  }\n}\n```\n\n\u003ca name=\"api-reference\"\u003e\u003c/a\u003e\n\n## 📖 API reference\n\n_Note: some generic parameters are omitted for clarity._\n\n### `createInjector`\n\nCreate a new `Injector\u003c{}\u003e`. You generally want to create one per application/request. If you're using `typed-inject` also in your unit tests, you probably want to create a fresh one for each test, for example in global test setup.\n\n### `Injector\u003cTContext\u003e`\n\nThe `Injector\u003cTContext\u003e` is the core interface of typed-inject. It provides the ability to inject your class or function with `injectClass` and `injectFunction` respectively. You can create new _child injectors_ from it using the `provideXXX` methods.\n\nThe `TContext` generic argument is a [lookup type](https://blog.mariusschulz.com/2017/01/06/typescript-2-1-keyof-and-lookup-types). The keys in this type are the tokens that can be injected, the values are the exact types of those tokens. For example, if `TContext extends { foo: string, bar: number }`, you can let a token `'foo'` be injected of type `string`, and a token `'bar'` of type `number`.\n\nTyped inject comes with only one implementation. The `rootInjector`. It implements `Injector\u003c{}\u003e` interface, meaning that it does not provide any tokens (except for [magic tokens](#-magic-tokens)). Import it with `import { rootInjector } from 'typed-inject'`. From the `rootInjector`, you can create child injectors. See [creating child injectors](#-creating-child-injectors) for more information.\n\n#### `injector.injectClass(injectable: InjectableClass)`\n\nThis method creates a new instance of class `injectable` by populating its constructor arguments from the injector and returns it.\n\nBasically it is a shortcut for resolving values from the injector and creating a new instance with those values:\n\n```ts\nconst logger = appInjector.resolve('logger');\nconst httpClient = appInjector.resolve('httpClient');\nconst service = new MyService(httpClient, logger);\n```\n\nAny instance created with `injectClass` will not be disposed when `dispose` is called. It is the caller's responsiblity to dispose it.\n\nWhen there are any problems in the dependency graph, it gives a compiler error.\n\n```ts\nclass Foo {\n  constructor(bar: number) {}\n  static inject = ['bar'] as const;\n}\nconst foo /*: Foo*/ = injector.injectClass(Foo);\n```\n\n#### `injector.injectFunction(fn: InjectableFunction)`\n\nThis method injects the function with requested tokens from the injector, invokes it and returns the result.\n\nIt is a shortcut for calling the provided function with the values from the injector.\n\n```ts\nconst logger = appInjector.resolve('logger');\nconst httpClient = appInjector.resolve('httpClient');\nconst request = doRequest(httpClient, logger);\n```\n\nWhen there are any problems in the dependency graph, it gives a compiler error.\n\n```ts\nfunction foo(bar: number) {\n  return bar + 1;\n}\nfoo.inject = ['bar'] as const;\nconst baz /*: number*/ = injector.injectFunction(Foo);\n```\n\n#### `injector.resolve(token: Token): CorrespondingType\u003cTContext, Token\u003e`\n\nThe `resolve` method lets you resolve tokens by hand.\n\n```ts\nconst foo = injector.resolve('foo');\n// Equivalent to:\nfunction retrieveFoo(foo: number) {\n  return foo;\n}\nretrieveFoo.inject = ['foo'] as const;\nconst foo2 = injector.injectFunction(retrieveFoo);\n```\n\n#### `injector.provideValue(token: Token, value: R): Injector\u003cChildContext\u003cTContext, Token, R\u003e\u003e`\n\nCreate a child injector that can provide value `value` for token `'token'`. The new child injector can resolve all tokens the parent injector can as well as `'token'`.\n\n```ts\nconst fooInjector = injector.provideValue('foo', 42);\n```\n\n#### `injector.provideFactory(token: Token, factory: InjectableFunction\u003cTContext\u003e, scope = Scope.Singleton): Injector\u003cChildContext\u003cTContext, Token, R\u003e\u003e`\n\nCreate a child injector that can provide a value using `factory` for token `'token'`. The new child injector can resolve all tokens the parent injector can and the new `'token'`.\n\nWith `scope` you can decide whether the value must be cached after the factory is invoked once. Use `Scope.Singleton` to enable caching (default), or `Scope.Transient` to disable caching.\n\n```ts\nconst fooInjector = injector.provideFactory('foo', () =\u003e 42);\nfunction loggerFactory(target: Function | undefined) {\n  return new Logger((target \u0026\u0026 target.name) || '');\n}\nloggerFactory.inject = [TARGET_TOKEN] as const;\nconst fooBarInjector = fooInjector.provideFactory(\n  'logger',\n  loggerFactory,\n  Scope.Transient,\n);\n```\n\n#### `injector.provideClass(token: Token, Class: InjectableClass\u003cTContext\u003e, scope = Scope.Singleton): Injector\u003cChildContext\u003cTContext, Token, R\u003e\u003e`\n\nCreate a child injector that can provide a value using instances of `Class` for token `'token'`. The new child injector can resolve all tokens the parent injector can, as well as the new `'token'`.\n\nScope is also supported here, for more info, see `provideFactory`.\n\n#### `injector.createChildInjector(): Injector\u003cTContext\u003e`\n\nCreate a child injector that can provide exactly the same as the parent injector. Contrary to its `provideXxx` counterparts,this will create a new disposable scope without providing additional injectable values.\n\n```ts\nconst parentInjector = createInjector().provideValue('foo', 'bar');\nfor (const task of tasks) {\n  try {\n    const scope = parentInjector.createChildInjector();\n    const foo = scope.provideClass('baz', DisposableBaz).injectClass(Foo);\n    foo.handle(task);\n  } finally {\n    await scope.dispose(); // Dispose the scope, including instances of DisposableBaz\n    // Next task gets a fresh scope\n  }\n}\n```\n\n#### `injector.dispose(): Promise\u003cvoid\u003e`\n\nUse `dispose` to explicitly dispose the `injector`. This will result in the following (in order):\n\n1. Call `dispose` on each child injector created from this injector.\n2. It will call `dispose` on any dependency created by the injector (if it exists) using `provideClass` or `provideFactory` (**not** `provideValue` or `injectXXX`).\n3. It will also await any promise that might have been returned by disposable dependencies.\n\n_Note: this behavior changed since v2. Before v2, the parent injector was always disposed before the child injector._\n_Note: this behavior changed again in v3, calling `dispose` on a child injector will **no longer** dispose it's parent injector and instead will dispose it's child injectors. The order of disposal is still child first._\n\nAfter an injector is disposed, you cannot use it anymore. Any attempt to do so will result in an `InjectorDisposedError` error.\n\nDisposing of your dependencies is always done asynchronously. You should take care to handle this appropriately. The best way to do that is to `await` the result of `myInjector.dispose()`.\n\n### `Scope`\n\nThe `Scope` enum indicates the scope of a provided injectable (class or factory). Possible values: `Scope.Transient` (new injection per resolve) or `Scope.Singleton` (inject once, and reuse values). It generally defaults to `Singleton`.\n\n### `tokens`\n\nThe `tokens` function is a simple helper method that makes sure that an `inject` array is filled with a [readonly tuple type filled with literal strings](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-0.html#rest-parameters-with-tuple-types). It is mostly there for backward compatibility reasons, since we can now use `as const`, but one might also simply prefer to use `tokens` instead.\n\n```ts\nconst inject = tokens('foo', 'bar');\n// Equivalent to:\nconst inject = ['foo', 'bar'] as const;\n```\n\n### `InjectableClass\u003cTContext, R, Tokens extends InjectionToken\u003cTContext\u003e[]\u003e`\n\nThe `InjectableClass` interface is used to identify the (static) interface of classes that can be injected. It is defined as follows:\n\n```ts\n{\n  new(...args: CorrespondingTypes\u003cTContext, Tokens\u003e): R;\n  readonly inject: Tokens;\n}\n```\n\nIn other words, it makes sure that the `inject` tokens is corresponding with the constructor types.\n\n### `InjectableFunction\u003cTContext, R, Tokens extends InjectionToken\u003cTContext\u003e[]\u003e`\n\nComparable to `InjectableClass`, but for (non-constructor) functions.\n\n### `Disposable`\n\nYou can implement the `Disposable` interface in your dependencies. It looks like this:\n\n```ts\ninterface Disposable {\n  dispose(): void;\n}\n```\n\nWith this, you can let the `Injector` call [your dispose method](#-disposing-provided-stuff).\n\n_Note:_ This is just a convenience interface. Due to TypeScripts structural typing system `typed-inject` calls your `dispose` method without you having to explicitly implement it.\n\n### `InjectionError`\n\nThe error class of which instances are thrown when an error occurs during injection or dependency resolving.\n\nAn example:\n\n```ts\nconst explosion = new Error('boom!');\nclass Boom {\n  constructor() {\n    throw explosion;\n  }\n}\nclass Prison {\n  constructor(public readonly child: Boom) {}\n  public static inject = ['boom'] as const;\n}\ntry {\n  rootInjector.provideClass('boom', Boom).injectClass(Prison);\n} catch (error) {\n  if (error instanceof InjectionError) {\n    error.path[0] === Prison;\n    error.path[1] === 'boom';\n    error.path[2] === Boom;\n    error.cause === explosion;\n  }\n}\n```\n\n#### `InjectionError.path`\n\nThis will contain the path that was taken to get to the error.\n\n#### `InjectionError.cause`\n\nThe original cause of the injection error.\n\n\u003ca name=\"commendation\"\u003e\u003c/a\u003e\n\n## 🤝 Commendation\n\nThis entire framework would not be possible without the awesome guys working on TypeScript. Guys like [Ryan](https://github.com/RyanCavanaugh), [Anders](https://github.com/ahejlsberg) and the rest of the team: a heartfelt thanks! 💖\n\nInspiration for the API with static `inject` method comes from years-long AngularJS development. Special thanks to the Angular team.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicojs%2Ftyped-inject","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnicojs%2Ftyped-inject","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnicojs%2Ftyped-inject/lists"}