docs: update README.md with detailed usage examples and service lifetime explanations
This commit is contained in:
@@ -2,6 +2,226 @@
|
||||
|
||||
A dependency injection container for [TypeScript](https://www.typescriptlang.org/) projects that is inspired by the [.NET](https://dotnet.microsoft.com/en-us/) DI container. It is designed to be simple, lightweight, and easy to use.
|
||||
|
||||
[](https://github.com/StevanFreeborn/netdi/actions/workflows/pull_request.yaml)
|
||||
[](https://codecov.io/gh/StevanFreeborn/netdi)
|
||||
[](https://github.com/StevanFreeborn/netdi/actions/workflows/publish.yaml)
|
||||
[](https://github.com/semantic-release/semantic-release)
|
||||

|
||||

|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- ✅ .NET-style service registration with different lifetimes (singleton, scoped, transient)
|
||||
- ✅ Constructor injection with decorators
|
||||
- ✅ Type-safe dependency resolution
|
||||
- ✅ Factory method support for complex instantiation scenarios
|
||||
- ✅ Scoped service lifetimes for per-request contexts
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install @stevanfreeborn/netdi
|
||||
|
||||
# yarn
|
||||
yarn add @stevanfreeborn/netdi
|
||||
|
||||
# pnpm
|
||||
pnpm add @stevanfreeborn/netdi
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Node.js >= 18.0.0
|
||||
- TypeScript with decorators and reflection metadata enabled
|
||||
|
||||
Add the following to your `tsconfig.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Here's a simple example of how to use netdi:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
ServiceCollection,
|
||||
createServiceIdentifier,
|
||||
injectable,
|
||||
inject
|
||||
} from '@stevanfreeborn/netdi';
|
||||
|
||||
// Define interfaces
|
||||
interface IGreeter {
|
||||
greet(name: string): string;
|
||||
}
|
||||
|
||||
interface IGreetingService {
|
||||
createGreeting(name: string): string;
|
||||
}
|
||||
|
||||
// Create service identifiers
|
||||
const greeterIdentifier = createServiceIdentifier<IGreeter>();
|
||||
const greetingServiceIdentifier = createServiceIdentifier<IGreetingService>();
|
||||
|
||||
// Implement services
|
||||
@injectable()
|
||||
class GreetingService implements IGreetingService {
|
||||
createGreeting(name: string): string {
|
||||
return `Hello, ${name}!`;
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
class Greeter implements IGreeter {
|
||||
constructor(
|
||||
@inject(greetingServiceIdentifier) private greetingService: IGreetingService
|
||||
) {}
|
||||
|
||||
greet(name: string): string {
|
||||
return this.greetingService.createGreeting(name);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up dependency injection
|
||||
const services = new ServiceCollection();
|
||||
|
||||
// Register services
|
||||
services.addSingleton(greetingServiceIdentifier, GreetingService);
|
||||
services.addScoped(greeterIdentifier, Greeter);
|
||||
|
||||
// Build service provider
|
||||
const serviceProvider = services.build();
|
||||
|
||||
// Resolve and use a service
|
||||
const greeter = serviceProvider.getService(greeterIdentifier);
|
||||
console.log(greeter.greet('World')); // Outputs: Hello, World!
|
||||
```
|
||||
|
||||
## Service Lifetimes
|
||||
|
||||
netdi supports three service lifetimes:
|
||||
|
||||
### Singleton
|
||||
|
||||
Singleton services are created once and shared by all consumers.
|
||||
|
||||
```typescript
|
||||
services.addSingleton(serviceIdentifier, Implementation);
|
||||
```
|
||||
|
||||
### Scoped
|
||||
|
||||
Scoped services are created once per scope. This is useful for services that should be shared within a request but not across requests.
|
||||
|
||||
```typescript
|
||||
services.addScoped(serviceIdentifier, Implementation);
|
||||
|
||||
// Create a scope
|
||||
const scope = serviceProvider.createScope();
|
||||
const scopedService = scope.serviceProvider.getService(serviceIdentifier);
|
||||
|
||||
// When done with the scope
|
||||
scope.dispose();
|
||||
```
|
||||
|
||||
### Transient
|
||||
|
||||
Transient services are created each time they are requested.
|
||||
|
||||
```typescript
|
||||
services.addTransient(serviceIdentifier, Implementation);
|
||||
```
|
||||
|
||||
## Factory Registration
|
||||
|
||||
For complex service instantiation, you can use factory methods:
|
||||
|
||||
```typescript
|
||||
services.addSingleton(serviceIdentifier, (provider) => {
|
||||
// Use the provider to get dependencies
|
||||
const dependency = provider.getService(dependencyIdentifier);
|
||||
|
||||
// Create and configure your service instance
|
||||
const instance = new MyService(dependency);
|
||||
instance.configure();
|
||||
|
||||
return instance;
|
||||
});
|
||||
```
|
||||
|
||||
## Creating Service Identifiers
|
||||
|
||||
Service identifiers help maintain type safety and prevent service conflicts:
|
||||
|
||||
```typescript
|
||||
// Create an identifier for a specific interface
|
||||
const userServiceIdentifier = createServiceIdentifier<IUserService>();
|
||||
|
||||
// Then use it for registration and resolution
|
||||
services.addSingleton(userServiceIdentifier, UserService);
|
||||
const userService = serviceProvider.getService(userServiceIdentifier);
|
||||
```
|
||||
|
||||
## Decorators
|
||||
|
||||
### @injectable()
|
||||
|
||||
Marks a class as injectable, allowing the container to create instances with dependencies:
|
||||
|
||||
```typescript
|
||||
@injectable()
|
||||
class MyService {
|
||||
constructor() {}
|
||||
}
|
||||
```
|
||||
|
||||
### @inject()
|
||||
|
||||
Specifies a dependency for a parameter:
|
||||
|
||||
```typescript
|
||||
class MyService {
|
||||
constructor(
|
||||
@inject(loggerIdentifier) private logger: ILogger,
|
||||
@inject(configIdentifier) private config: IConfig
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Service Disposal
|
||||
|
||||
Both service providers and scopes implement a `dispose()` method:
|
||||
|
||||
```typescript
|
||||
// Dispose the root provider
|
||||
serviceProvider.dispose();
|
||||
|
||||
// Dispose a scope
|
||||
const scope = serviceProvider.createScope();
|
||||
// ... use scope
|
||||
scope.dispose();
|
||||
```
|
||||
|
||||
### Type Safety
|
||||
|
||||
netdi is designed to be fully type-safe. The `getService()` method returns the exact type associated with the service identifier:
|
||||
|
||||
```typescript
|
||||
// TypeScript knows this is an IUserService
|
||||
const userService = serviceProvider.getService(userServiceIdentifier);
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Stevan Freeborn](https://github.com/StevanFreeborn)
|
||||
|
||||
Reference in New Issue
Block a user