Skip to main content Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/InugamiDev/ultrathink-oss --skill dependency-injectionLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Plus depuis ce dépôt Unified design foundations — design system architecture, tokens, component specs, visual principles, creative vision, figma integration, plus brand design system loader (66 real brands via DESIGN.md). Absorbs design, design-system, design-systems, design-principles, design-router, creative-vision, figma, design-md.
Render, summarize, and present markdown documents and structured content in multiple output modes
Ultra UI skill - combines Google's DESIGN.md spec (machine-readable design tokens) with the ui-ux-pro-max knowledge base (91 styles, 161 palettes, 73 font pairings, 161 products, 104 UX guidelines, 25 chart types). Generates lint-clean DESIGN.md files, validates token references and WCAG contrast, exports Tailwind/DTCG tokens, and diffs design systems version-over-version.
Métiers associés SOC
Basé sur la classification professionnelle SOC
name dependency-injection description Dependency injection patterns — IoC containers, service registration, lifetime scoping, and testing. layer utility category architecture triggers ["dependency injection","IoC","inversion of control","DI container","service provider"] inputs ["DI architecture decisions","Service registration and lifetime scoping","IoC container selection and configuration","Testing with dependency injection"] outputs ["DI container setup and configuration","Service registration patterns","Lifetime management strategies","Testable architectures with DI"] linksTo ["nestjs","typescript-patterns","testing-patterns"] linkedFrom [] preferredNextSkills ["nestjs","typescript-patterns","testing-patterns"] fallbackSkills [] riskLevel low memoryReadPolicy selective memoryWritePolicy none sideEffects []
Dependency Injection Patterns
Purpose
Provide expert guidance on dependency injection (DI) and inversion of control (IoC) patterns including container configuration, service lifetimes, composition roots, and how DI enables testability. Covers both framework-based DI (NestJS, Angular) and standalone containers (tsyringe, inversify, awilix).
Core Concepts
Dependency Injection inverts the control of dependency creation. Instead of a class creating its own dependencies, they are provided (injected) from the outside.
class OrderService {
private db = new PostgresDatabase ();
private mailer = new SmtpMailer ();
async createOrder (data : CreateOrderDto ) {
const order = await this .db .insert ('orders' , data);
await this .mailer .send (data.email , 'Order confirmed' );
return order;
}
}
class OrderService {
constructor (
private readonly db : Database ,
private : ,
) {}
( ) {
order = . . ( , data);
. . (data. , );
order;
}
}
readonly
mailer
Mailer
async
createOrder
data : CreateOrderDto
const
await
this
db
insert
'orders'
await
this
mailer
send
email
'Order confirmed'
return
DI Patterns
Constructor Injection (Preferred) Dependencies provided via the constructor. Most explicit and testable:
interface Logger {
info (message : string ): void ;
error (message : string , error ?: Error ): void ;
}
interface UserRepository {
findById (id : string ): Promise <User | null >;
save (user : User ): Promise <User >;
}
class UserService {
constructor (
private readonly userRepo : UserRepository ,
private readonly logger : Logger ,
) {}
async getUser (id : string ): Promise <User > {
this .logger .info (`Fetching user ${id} ` );
const user = await this .userRepo .findById (id);
if (!user) throw new NotFoundException (`User ${id} not found` );
return user;
}
}
Factory Pattern When the dependency needs runtime parameters:
interface ConnectionFactory {
create (config : ConnectionConfig ): Connection ;
}
class DatabaseService {
constructor (private readonly connectionFactory : ConnectionFactory ) {}
connect (config : ConnectionConfig ) {
return this .connectionFactory .create (config);
}
}
Strategy Pattern with DI Inject different implementations based on context:
interface PaymentProcessor {
charge (amount : number , currency : string ): Promise <PaymentResult >;
}
class StripeProcessor implements PaymentProcessor {
async charge (amount : number , currency : string ) { }
}
class PayPalProcessor implements PaymentProcessor {
async charge (amount : number , currency : string ) { }
}
class PaymentService {
constructor (
private readonly processors : Map <string , PaymentProcessor >,
) {}
async processPayment (method : string , amount : number , currency : string ) {
const processor = this .processors .get (method);
if (!processor) throw new Error (`Unknown payment method: ${method} ` );
return processor.charge (amount, currency);
}
}
Service Lifetimes Lifetime Description Use Case Singleton One instance for the entire app Stateless services, config, loggers Transient New instance on every injection Stateful services, request-specific logic Scoped One instance per scope (e.g., HTTP request) Database connections, user context
import { container, singleton, injectable } from 'tsyringe' ;
@singleton ()
class ConfigService {
get (key : string ): string { }
}
@injectable ()
class RequestHandler {
constructor (private config : ConfigService ) {}
}
const requestContainer = container.createChildContainer ();
requestContainer.register ('RequestContext' , { useValue : { userId : '123' } });
IoC Containers
tsyringe (Lightweight, TypeScript-native)
import 'reflect-metadata' ;
import { container } from 'tsyringe' ;
container.register <Database >('Database' , { useClass : PostgresDatabase });
container.register <Mailer >('Mailer' , { useClass : SmtpMailer });
container.register <Logger >('Logger' , { useClass : PinoLogger });
const orderService = container.resolve (OrderService );
import { injectable, inject } from 'tsyringe' ;
@injectable ()
class OrderService {
constructor (
@inject ('Database' ) private readonly db : Database ,
@inject ('Mailer' ) private readonly mailer : Mailer ,
) {}
}
awilix (No decorators, function-oriented)
import { createContainer, asClass, asFunction, Lifetime } from 'awilix' ;
const container = createContainer ();
container.register ({
userRepository : asClass (PostgresUserRepository ).singleton (),
orderRepository : asClass (PostgresOrderRepository ).singleton (),
logger : asClass (PinoLogger ).singleton (),
userService : asClass (UserService ).scoped (),
orderService : asClass (OrderService ).scoped (),
dbConnection : asFunction (({ config } ) =>
createPool (config.databaseUrl )
).singleton (),
});
app.use ((req, _res, next ) => {
req.scope = container.createScope ();
req.scope .register ({ requestId : asValue (crypto.randomUUID ()) });
next ();
});
NestJS Built-in DI
@Module ({
providers : [
UserService ,
{ provide : 'MAILER' , useClass : SmtpMailer },
{
provide : 'DB_POOL' ,
useFactory : (config : ConfigService ) => createPool (config.get ('DATABASE_URL' )),
inject : [ConfigService ],
},
{ provide : 'APP_VERSION' , useValue : '1.0.0' },
],
})
export class UsersModule {}
Composition Root The composition root is the single place where the entire dependency graph is wired. Keep it at the app entry point:
import { container } from './container' ;
async function bootstrap ( ) {
container.register <Database >('Database' , { useClass : PostgresDatabase });
container.register <Cache >('Cache' , { useClass : RedisCache });
container.register <Mailer >('Mailer' , { useClass : ResendMailer });
container.register <Logger >('Logger' , { useClass : PinoLogger });
const app = container.resolve (App );
await app.start ();
}
bootstrap ();
Rules for the composition root:
It is the ONLY place that references concrete implementations
All other code depends on abstractions (interfaces/types)
Easy to swap implementations for testing or different environments
Testing with DI Unit tests — inject mocks directly:
describe ('OrderService' , () => {
let service : OrderService ;
let mockDb : jest.Mocked <Database >;
let mockMailer : jest.Mocked <Mailer >;
beforeEach (() => {
mockDb = {
insert : jest.fn (),
findById : jest.fn (),
} as any ;
mockMailer = {
send : jest.fn ().mockResolvedValue (undefined ),
} as any ;
service = new OrderService (mockDb, mockMailer);
});
it ('creates order and sends confirmation email' , async () => {
mockDb.insert .mockResolvedValue ({ id : '1' , status : 'created' });
await service.createOrder ({
email : 'user@test.com' ,
items : [{ productId : 'p1' , qty : 2 }],
});
expect (mockDb.insert ).toHaveBeenCalledWith ('orders' , expect.any (Object ));
expect (mockMailer.send ).toHaveBeenCalledWith ('user@test.com' , 'Order confirmed' );
});
});
Integration tests — override specific registrations:
describe ('OrderService (integration)' , () => {
let testContainer : typeof container;
beforeEach (() => {
testContainer = container.createChildContainer ();
testContainer.register <Mailer >('Mailer' , { useClass : NoopMailer });
});
it ('persists order to database' , async () => {
const service = testContainer.resolve (OrderService );
const order = await service.createOrder ({ });
expect (order.id ).toBeDefined ();
});
});
Best Practices
Depend on abstractions — Inject interfaces, not concrete classes.
Constructor injection only — Avoid property injection and service locator pattern.
Single composition root — Wire everything in one place at app startup.
Prefer singleton for stateless services — Transient/scoped only when state is per-request.
No new in business logic — If a class creates its own dependencies, it cannot be tested in isolation.
Avoid circular dependencies — Restructure into a shared module or use events.
Keep containers out of business logic — Only the composition root touches the container.
Use factory providers for runtime config — When a dependency needs config values.
Scope database connections per request — Prevent connection leaks and enable per-request transactions.
Test without the container — Unit tests should inject mocks via constructor, no container needed.
Common Pitfalls Pitfall Problem Fix Service locator anti-pattern container.resolve() called inside business logicInject via constructor; only resolve at the composition root Missing reflect-metadata Decorator-based DI fails silently Import reflect-metadata at app entry point Circular dependency Container throws at resolution time Break the cycle with events, mediator, or forwardRef() Overusing transient scope High memory usage, GC pressure Default to singleton; use transient only when stateful Injecting concrete classes Tight coupling, hard to mock Define interfaces and inject those Container in unit tests Tests become slow integration tests Inject mocks directly via constructor