<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Valid Lab</title>
    <description>The latest articles on DEV Community by Valid Lab (@valid-lab).</description>
    <link>https://dev.to/valid-lab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3947538%2F48ebecf5-6500-4ae4-bb56-372dfe2f81bb.png</url>
      <title>DEV Community: Valid Lab</title>
      <link>https://dev.to/valid-lab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/valid-lab"/>
    <language>en</language>
    <item>
      <title>Wyrly DI: Type-safe Dependency Injection for Modern TypeScript</title>
      <dc:creator>Valid Lab</dc:creator>
      <pubDate>Sat, 23 May 2026 11:15:57 +0000</pubDate>
      <link>https://dev.to/valid-lab/wyrly-di-type-safe-dependency-injection-for-modern-typescript-1c1f</link>
      <guid>https://dev.to/valid-lab/wyrly-di-type-safe-dependency-injection-for-modern-typescript-1c1f</guid>
      <description>&lt;p&gt;We have released &lt;strong&gt;Wyrly DI&lt;/strong&gt;, a dependency injection toolkit for TypeScript.&lt;/p&gt;

&lt;p&gt;Wyrly DI is designed for modern TypeScript applications that want dependency&lt;br&gt;
injection without relying on &lt;code&gt;reflect-metadata&lt;/code&gt;, &lt;code&gt;emitDecoratorMetadata&lt;/code&gt;, legacy&lt;br&gt;
decorators, or parameter decorators.&lt;/p&gt;

&lt;p&gt;It focuses on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;standard decorators&lt;/li&gt;
&lt;li&gt;type-safe tokens&lt;/li&gt;
&lt;li&gt;explicit dependency definitions&lt;/li&gt;
&lt;li&gt;request scopes for web applications&lt;/li&gt;
&lt;li&gt;inspectable and validatable dependency graphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, "standard decorators" means TC39 decorators supported by&lt;br&gt;
TypeScript 5.0 and later. This is different from the older&lt;br&gt;
&lt;code&gt;experimentalDecorators&lt;/code&gt; model that many existing DI libraries were built&lt;br&gt;
around.&lt;/p&gt;
&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/valid-lab/wyrly" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jsr.io/@wyrly/core" rel="noopener noreferrer"&gt;@wyrly/core on JSR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@wyrly/core" rel="noopener noreferrer"&gt;@wyrly/core on npm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/valid-lab/wyrly/tree/main/examples" rel="noopener noreferrer"&gt;Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Why another DI toolkit?
&lt;/h2&gt;

&lt;p&gt;Many TypeScript DI libraries use runtime metadata to infer constructor&lt;br&gt;
dependencies.&lt;/p&gt;

&lt;p&gt;That can be convenient, but it also means important dependency information can&lt;br&gt;
become hidden behind runtime metadata and decorator behavior.&lt;/p&gt;

&lt;p&gt;Wyrly DI takes a more explicit approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@wyrly/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserRepositoryToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserRepository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;UserRepositoryToken&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;lifetime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scoped&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GetUserUseCase&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By declaring &lt;code&gt;deps&lt;/code&gt;, dependencies remain visible to code review, static&lt;br&gt;
analysis, CI, and AI-assisted development tools.&lt;/p&gt;

&lt;p&gt;With standard decorators, Wyrly DI does not try to read constructor parameter&lt;br&gt;
types from &lt;code&gt;reflect-metadata&lt;/code&gt;. You can still use normal constructor injection,&lt;br&gt;
such as &lt;code&gt;constructor(private readonly users: UserRepository)&lt;/code&gt;, but the&lt;br&gt;
dependency mapping is declared explicitly with &lt;code&gt;deps&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the example above, &lt;code&gt;UserRepositoryToken&lt;/code&gt; is used because TypeScript&lt;br&gt;
interfaces do not exist at runtime. When the dependency is a class, the class&lt;br&gt;
itself can also be used as a token. In other words, you can use typed tokens for&lt;br&gt;
interfaces and class tokens for classes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Type-safe tokens
&lt;/h2&gt;

&lt;p&gt;TypeScript interfaces disappear at runtime, so interface-based dependencies need&lt;br&gt;
a runtime token.&lt;/p&gt;

&lt;p&gt;Wyrly DI provides typed tokens for that purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;UserRepositoryToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UserRepository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;UserRepositoryToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// users: UserRepository&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resolved value is inferred as &lt;code&gt;UserRepository&lt;/code&gt;, so interface-based&lt;br&gt;
dependencies can still be used in a type-safe way.&lt;/p&gt;
&lt;h2&gt;
  
  
  Request scopes
&lt;/h2&gt;

&lt;p&gt;Web applications often need dependencies that are different for each request.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current user&lt;/li&gt;
&lt;li&gt;request&lt;/li&gt;
&lt;li&gt;response&lt;/li&gt;
&lt;li&gt;unit of work&lt;/li&gt;
&lt;li&gt;DataLoader&lt;/li&gt;
&lt;li&gt;request-scoped cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wyrly DI's web adapters are built around this model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1 HTTP request = 1 DI scope
1 GraphQL request = 1 DI scope
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request scope is not the only supported lifetime. The core package supports&lt;br&gt;
&lt;code&gt;singleton&lt;/code&gt;, &lt;code&gt;scoped&lt;/code&gt;, and &lt;code&gt;transient&lt;/code&gt;, so you can model application-wide&lt;br&gt;
dependencies, per-request dependencies, and dependencies that should be created&lt;br&gt;
on every resolution.&lt;/p&gt;

&lt;p&gt;For example, the Hono adapter creates a scope per request in middleware, then&lt;br&gt;
lets handlers resolve dependencies from that scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Hono&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hono&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createContainer&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@wyrly/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;di&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getDI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;HonoDIVariables&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@wyrly/hono&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Hono&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HonoDIVariables&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createContainer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;di&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/users/:id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getDI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;usecase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GetUserUseCase&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;usecase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Inspecting and validating the dependency graph
&lt;/h2&gt;

&lt;p&gt;Wyrly DI can inspect and validate the dependency graph.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, validation can detect dangerous lifetime relationships, such as a&lt;br&gt;
singleton depending on a scoped dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;singleton -&amp;gt; scoped dependency
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That kind of relationship can cause subtle bugs, such as request-specific data&lt;br&gt;
being held by a singleton.&lt;/p&gt;

&lt;p&gt;You can also put graph validation in a test and fail CI when the composition&lt;br&gt;
root becomes invalid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;assertEquals&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@std/assert&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DI graph is valid&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;issues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This may be unnecessary for very small applications.&lt;/p&gt;

&lt;p&gt;But in applications that care about boundaries, such as DDD or Clean&lt;br&gt;
Architecture style codebases, dependency problems become more expensive to fix&lt;br&gt;
when they are discovered late.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a singleton service accidentally depends on a request-scoped &lt;code&gt;CurrentUser&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;an application use case becomes too coupled to infrastructure details&lt;/li&gt;
&lt;li&gt;a composition root grows without anyone noticing an invalid dependency
relationship&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Validating the graph in CI helps catch those structural problems before they&lt;br&gt;
become normal parts of the codebase.&lt;/p&gt;
&lt;h2&gt;
  
  
  Published packages
&lt;/h2&gt;

&lt;p&gt;The following packages are available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@wyrly/core
@wyrly/next
@wyrly/express
@wyrly/hono
@wyrly/fresh
@wyrly/graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use JSR for Deno:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deno add jsr:@wyrly/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use npm for Node.js and Bun:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @wyrly/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install adapters as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @wyrly/hono
npm &lt;span class="nb"&gt;install&lt;/span&gt; @wyrly/next
npm &lt;span class="nb"&gt;install&lt;/span&gt; @wyrly/graphql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  When Wyrly DI may be a good fit
&lt;/h2&gt;

&lt;p&gt;Wyrly DI may fit your project if you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;avoid &lt;code&gt;reflect-metadata&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;use DI with TypeScript standard decorators&lt;/li&gt;
&lt;li&gt;make a composition root explicit in DDD or Clean Architecture&lt;/li&gt;
&lt;li&gt;use request scopes with Next.js, Hono, Express, or GraphQL&lt;/li&gt;
&lt;li&gt;make the dependency graph visible in review and CI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When another tool may be a better fit
&lt;/h2&gt;

&lt;p&gt;Another tool may be a better fit if you want:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a full-stack framework with controllers, modules, authentication, and
configuration management&lt;/li&gt;
&lt;li&gt;automatic scanning and registration as the primary workflow&lt;/li&gt;
&lt;li&gt;parameter decorator-based injection&lt;/li&gt;
&lt;li&gt;compatibility with an existing app that deeply depends on &lt;code&gt;reflect-metadata&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wyrly DI intentionally separates a small explicit DI core from framework&lt;br&gt;
adapters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;The repository includes runnable examples for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DDD composition root&lt;/li&gt;
&lt;li&gt;Hono API&lt;/li&gt;
&lt;li&gt;Express API&lt;/li&gt;
&lt;li&gt;Next.js App Router&lt;/li&gt;
&lt;li&gt;GraphQL request scope&lt;/li&gt;
&lt;li&gt;DataLoader pattern&lt;/li&gt;
&lt;li&gt;dependency graph validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See the examples here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/valid-lab/wyrly/tree/main/examples" rel="noopener noreferrer"&gt;github.com/valid-lab/wyrly/tree/main/examples&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Wyrly DI is a toolkit for making TypeScript dependency injection explicit,&lt;br&gt;
analyzable, and practical for request-scoped web applications.&lt;/p&gt;

&lt;p&gt;The design principles are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;explicit dependency definitions over implicit auto-resolution&lt;/li&gt;
&lt;li&gt;inspectable structure over hidden behavior&lt;/li&gt;
&lt;li&gt;standard decorators over legacy decorators&lt;/li&gt;
&lt;li&gt;type-safe tokens over string-only tokens&lt;/li&gt;
&lt;li&gt;composition roots over automatic scanning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If that sounds useful for your project, start with &lt;code&gt;@wyrly/core&lt;/code&gt; and the example&lt;br&gt;
closest to your framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/valid-lab/wyrly" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jsr.io/@wyrly/core" rel="noopener noreferrer"&gt;JSR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@wyrly/core" rel="noopener noreferrer"&gt;npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>typescript</category>
      <category>deno</category>
      <category>node</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
