Getting Started
Decorator-free Dependency Injection for TypeScript
⚡ The AI Way
Let AI do the heavy lifting. Copy our prompt, paste it to Claude/ChatGPT, and you're done.
AI Setup (60 seconds)🛠️ The Manual Way
Prefer hands-on? Follow step-by-step instructions to set up NovaDI yourself.
Manual Setup⚡ AI-Assisted Setup (Recommended)
NovaDI is designed to be AI-friendly. Instead of memorizing APIs and patterns, just give your AI assistant this prompt and let it handle the setup.
Dependency injection frameworks traditionally have steep learning curves. NovaDI embraces modern development: give AI the context it needs, and it writes clean DI code that follows best practices automatically.
Step 1: Copy the Prompt
Copy this entire prompt and paste it into Claude, ChatGPT, or your favorite AI coding assistant:
I want to use the @novadi/core dependency injection library in my TypeScript project.
Key Principles:
- Package: @novadi/core
- NO decorators/annotations in business code
- Convention over configuration
- Uses .as<T>() and .resolveType<T>()
- TypeScript transformer handles type names automatically
Core API:
1. Import: import { Container } from '@novadi/core'
2. Build container:
const container = new Container()
const builder = container.builder()
3. Register services:
builder.registerType(ConsoleLogger).as<ILogger>().singleInstance()
4. Autowire dependencies BY CONVENTION (recommended):
builder.registerType(UserService).as<UserService>().autoWire()
// Parameters automatically match registered interfaces by naming convention
5. Build and resolve:
const app = builder.build()
const service = app.resolveType<UserService>()
Lifetimes:
- .singleInstance() - singleton
- .instancePerDependency() - transient (DEFAULT)
- .instancePerRequest() - per resolution tree
AutoWire (Convention Over Configuration):
- Automatic: .autoWire() - matches parameters to interfaces by naming convention
- Explicit: .autoWire({ map: { logger: (c) => c.resolveType<ILogger>() } })
- Use automatic for ALL services, explicit only for primitives/values
Transformer Setup (tsconfig.json):
{
"compilerOptions": {
"plugins": [
{ "transform": "@novadi/core/transformer" }
]
}
}
Then: npm install -D ts-patch && npx ts-patch install
Simple Hello World example:
```typescript
import { Container } from '@novadi/core'
interface IGreeter {
greet(name: string): string
}
class ConsoleGreeter implements IGreeter {
greet(name: string): string {
return `Hello, ${name}!`
}
}
class Application {
constructor(private greeter: IGreeter) {}
run() {
console.log(this.greeter.greet('World'))
}
}
// Composition Root
const container = new Container()
const builder = container.builder()
builder.registerType(ConsoleGreeter).as<IGreeter>().singleInstance()
builder.registerType(Application).as<Application>().autoWire() // Convention!
const app = builder.build()
const application = app.resolveType<Application>()
application.run() // Outputs: Hello, World!
```
Please help me set up NovaDI following these patterns.
Step 2: Let AI Set It Up
Your AI assistant will:
- Install
@novadi/core - Configure the TypeScript transformer
- Create a basic container setup
- Write clean, decorator-free code following NovaDI conventions
Step 3: Start Coding
That's it! Your project is now set up with dependency injection. Start writing your services:
// Your business logic - clean and framework-free
interface IUserRepository {
findById(id: string): Promise
}
class UserRepository implements IUserRepository {
async findById(id: string): Promise {
// Database logic
}
}
class UserService {
constructor(private userRepo: IUserRepository) {}
async getUser(id: string) {
return this.userRepo.findById(id)
}
}
// Composition Root (AI can help set this up)
builder.registerType(UserRepository).as().singleInstance()
builder.registerType(UserService).as().autoWire() // ✨ Convention!
🛠️ Manual Setup
Prefer to set things up yourself? Here's the step-by-step Documentation.
1. Installation
npm install @novadi/core
# or
yarn add @novadi/core
# or
pnpm add @novadi/core
2. Transformer Setup
The TypeScript transformer automatically injects type names at compile-time. Choose one method:
Option A: Modern Bundlers (Recommended ⭐)
Use unplugin for universal bundler support:
// vite.config.ts
import { defineConfig } from 'vite'
import { NovadiUnplugin } from '@novadi/core/unplugin'
export default defineConfig({
plugins: [NovadiUnplugin.vite()]
})
// webpack.config.js
const { NovadiUnplugin } = require('@novadi/core/unplugin')
module.exports = {
plugins: [NovadiUnplugin.webpack()]
}
// rollup.config.js
import { NovadiUnplugin } from '@novadi/core/unplugin'
export default {
plugins: [NovadiUnplugin.rollup()]
}
// esbuild.config.js
const { NovadiUnplugin } = require('@novadi/core/unplugin')
require('esbuild').build({
plugins: [NovadiUnplugin.esbuild()]
})
Option B: TypeScript Compiler (tsc)
For direct tsc compilation, use ts-patch:
npm install -D ts-patch
npx ts-patch install
Add to tsconfig.json:
{
"compilerOptions": {
"plugins": [
{ "transform": "@novadi/core/transformer" }
]
}
}
You can provide type names manually, but this defeats the purpose of NovaDI's clean API. Only use this for runtime-only environments (tsx, ts-node) with no build step. See docs.
3. Basic Usage
Create your first container:
import { Container } from '@novadi/core'
// 1. Define your services (clean code, no decorators!)
interface ILogger {
log(message: string): void
}
class ConsoleLogger implements ILogger {
log(message: string) {
console.log(`[LOG] ${message}`)
}
}
class UserService {
constructor(private logger: ILogger) {}
createUser(name: string) {
this.logger.log(`Creating user: ${name}`)
}
}
// 2. Configure container (Composition Root)
const container = new Container()
const builder = container.builder()
// Register implementations
builder.registerType(ConsoleLogger).as().singleInstance()
// AutoWire does ALL the wiring by convention!
builder.registerType(UserService).as().autoWire()
const app = builder.build()
// 3. Resolve and use
const userService = app.resolveType()
userService.createUser('Alice') // [LOG] Creating user: Alice
.autoWire() - convention over configuration.
🚀 Next Steps
📚 Complete Documentation
Learn about lifetimes, patterns, and advanced features
Read the Documentation →