Skip to main content

Guides

Task-oriented documentation for common DiCaf workflows. Start with Getting Started if you are new to the library.

Table of contents

  • Getting Started — install DiCaf, create your first container, and resolve your first dependency.

  • Configuring the Container — all DiCaf constructor options: default scope, lazy mode, profiles, scope validation, circular reference detection, parent containers, and metadata readers.

  • Modules — organize bindings into reusable module functions, name them for debugging, write async modules, and create child containers.

  • Decorators — annotate classes with @Injectable, @Configuration, @Provides, and all related decorators to declare dependencies without writing module functions.

  • Factory Classes — use @Configuration + @Provides to produce bindings from factory methods: third-party types, assembled values, and anything @Injectable cannot cover alone.

  • Abstract Classes — register multiple implementations of an abstract class, inject all of them with allOf, and select between them using @Named, @Primary, and @ConditionalOn.

  • Interfaces — use symbol tokens as runtime keys for TypeScript interfaces, with the same injection patterns as abstract classes.

  • Collections — inject all bindings under a key as an array with allOf(), or as a named map with mapped().

  • Object Injection — inject a group of dependencies as a single plain object using object(), including nested specs and optional properties.

  • Building Instances — use build() for one-off instances and builder() for reusable compiled factories, both backed by container bindings.

  • Functions — bind plain functions with toFunction() to produce closures, plain objects, or objects with methods, with dependencies injected positionally.

  • Factory — bind a raw factory function with toFactory() to access the container directly at resolution time; useful for dynamic or conditional dependencies.

  • Conditional Bindings — register implementations only when a predicate passes at init time: region flags, env vars, feature toggles, or presence of another binding.

  • Fallback Bindings — mark a binding as a last-resort default, active only when no other non-fallback binding is registered for the same key; the standard pattern for overridable library defaults.

  • Lazy Bindings — defer construction of a binding until its first resolution; reduce startup time for expensive services and break circular dependency cycles.

  • Profiles — group bindings under named profiles (test, production, eu) and activate them declaratively via the container profiles option.

  • Mixing Scopes — safely inject shorter-lived dependencies into longer-lived components using provide() and Provider<T>; scope validation options.

  • Async Bindings — bind keys to async factories using toAsyncFactory(), @UseAsyncFactory, or @Async + @Provides; constraints and ordering rules.

  • Testing — write isolated tests with TestContainer: override bindings, focus on a dependency subtree, drop async bindings, and snapshot the global decorator registry.

  • Scanning Files — use scan() to auto-import all decorated source files in a directory, eliminating manual import lists in large codebases.

  • Dependency Graph — build and render the container's dependency graph as text, Markdown, Mermaid, DOT, or JSON.