Confronto
La maggior parte dei container DI nell'ecosistema TypeScript si appoggia a reflect-metadata e ai decorator per la scoperta automatica delle dipendenze. TinyDI prende la posizione opposta — ecco esattamente come si confronta questo compromesso.
TinyDI vs. TSyringe
| TinyDI | TSyringe | |
|---|---|---|
| Scoperta delle dipendenze | Esplicita, tramite factory | Automatica, tramite decorator + reflect-metadata |
| Decorator richiesti | No | Sì (@injectable, @inject, ...) |
| Flag del compilatore richiesti | Nessuno | experimentalDecorators, emitDecoratorMetadata |
| Dipendenze a runtime | Nessuna | reflect-metadata |
| Identità dei token | Token<T> basato su symbol | Token stringa o classi |
| Lifetime | Singleton, Transient | Singleton, Transient, ResolutionScoped, ContainerScoped |
TSyringe è un'ottima scelta se vuoi la constructor injection automatica e non ti dispiace avere decorator e reflect-metadata nel progetto. TinyDI scambia quella comodità con esplicitezza e una superficie più piccola.
TinyDI vs. InversifyJS
| TinyDI | InversifyJS | |
|---|---|---|
| Scoperta delle dipendenze | Esplicita, tramite factory | Automatica, tramite decorator + reflect-metadata |
| Decorator richiesti | No | Sì (@injectable, @inject, ...) |
| Flag del compilatore richiesti | Nessuno | experimentalDecorators, emitDecoratorMetadata |
| Dipendenze a runtime | Nessuna | reflect-metadata |
| Concetti da imparare | Token, Container, ServiceLifetime | Container, moduli, binding, scope, middleware |
| Lifetime | Singleton, Transient | Singleton, Transient, Request, scope personalizzati |
InversifyJS offre un set di funzionalità molto più ampio (moduli, middleware, multi-injection, tagging) al costo di una superficie API più grande e di una dipendenza a runtime dalla reflection. TinyDI copre intenzionalmente una fetta molto più piccola e semplice dello stesso problema.
TinyDI vs. una composition root scritta a mano
Molti developer esperti evitano del tutto un container DI: un unico file collega ogni dipendenza a mano con semplici chiamate a funzione. È proprio quella composition root, non un altro container, il vero concorrente di TinyDI nella maggior parte dei casi.
| TinyDI | Composition root scritta a mano | |
|---|---|---|
| Scoperta delle dipendenze | Esplicita, tramite factory | Esplicita, tramite semplici chiamate a funzione |
| Rilevamento dipendenze circolari | Automatico — lancia CircularDependencyError con il ciclo completo | Manuale — un ciclo lancia un errore runtime non correlato oppure si risolve silenziosamente in undefined, a seconda dell'ordine di caricamento dei moduli |
| Gestione dei lifetime | Integrata: Singleton o Transient, scelta per ogni registrazione | Scritta a mano: i singleton sono tipicamente costanti a livello di modulo, i transient richiedono una funzione factory manuale |
| Sostituire implementazioni nei test | remove() + registerInstance() su qualsiasi token | Di solito richiede di modificare la composition root stessa, o un punto di passaggio manuale dei parametri |
| Costo a runtime | Una lookup su Map per ogni chiamata a resolve() | Nessuno — chiamate a funzione dirette |
| Concetti da imparare | Token, Container, ServiceLifetime | Nessuno — è il linguaggio che già conosci |
Una composition root scritta a mano è una scelta perfettamente valida per un progetto piccolo con poche dipendenze. TinyDI ripaga soprattutto quando il debug delle dipendenze circolari, la gestione coerente dei lifetime, o la sostituzione di finte implementazioni nei test iniziano a costare tempo reale da fare a mano.