Skip to content

What is NeoSyringe?

NeoSyringe is a next-generation dependency injection system for TypeScript that shifts resolution from runtime to build-time.

The Problem with Traditional DI

Traditional DI containers (InversifyJS, tsyringe, Awilix) all work the same way:

typescript
// Traditional approach
@injectable()
class UserService {
  constructor(@inject(TYPES.ILogger) private logger: ILogger) {}
}

// At runtime
container.resolve(UserService); // ← Resolution happens HERE

This approach has several drawbacks:

IssueImpact
Runtime overheadDI container code shipped to production
Reflection requiredNeed reflect-metadata and decorators
Interface erasureMust use Symbols or string tokens manually
Late errorsMissing bindings only discovered at runtime
Framework couplingClasses polluted with DI decorators

The NeoSyringe Solution

NeoSyringe works as a compiler plugin that analyzes your configuration and generates optimized code:

typescript
// Your code (pure TypeScript!)
interface ILogger {
  log(msg: string): void;
}

class UserService {
  constructor(private logger: ILogger) {}
}

// Configuration
export const container = defineBuilderConfig({
  injections: [
    { token: useInterface<ILogger>(), provider: ConsoleLogger },
    { token: UserService }
  ]
});

At build time, this becomes:

typescript
// Generated code (no DI library!)
function create_UserService(container) {
  return new UserService(container.resolve("ILogger"));
}

class NeoContainer {
  resolve(token) {
    if (token === "ILogger") return new ConsoleLogger();
    if (token === UserService) return create_UserService(this);
  }
}

export const container = new NeoContainer();

Key Advantages

🚀 Zero Runtime Overhead

No DI library shipped to production. Just pure factory functions that create instances directly.

✨ Native Interface Support

Use useInterface<ILogger>() instead of managing Symbols. The compiler generates unique IDs automatically.

🛡️ Compile-Time Safety

Errors are detected in your IDE before you even save the file:

  • Circular dependencies
  • Missing bindings
  • Duplicate registrations
  • Type mismatches

📦 Pure Classes

Your business classes have zero DI dependencies:

typescript
// ✅ Pure TypeScript class
class UserService {
  constructor(private logger: ILogger) {}
}

// ❌ Traditional approach (polluted)
@injectable()
class UserService {
  constructor(@inject(TYPES.ILogger) private logger: ILogger) {}
}

🔄 Gradual Migration

Bridge existing containers while migrating:

typescript
export const container = defineBuilderConfig({
  useContainer: legacyTsyringeContainer, // ← Delegate to legacy
  injections: [
    { token: NewService } // New services in NeoSyringe
  ]
});

How It Works

┌─────────────────────────────────────────────────────────────┐
│                      BUILD TIME                              │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  1. defineBuilderConfig({...})                              │
│              │                                               │
│              ▼                                               │
│  2. TypeScript Plugin analyzes configuration                │
│              │                                               │
│              ▼                                               │
│  3. Generates optimized NeoContainer class                  │
│              │                                               │
│              ▼                                               │
│  4. Replaces defineBuilderConfig with generated code        │
│                                                              │
└─────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────┐
│                       RUNTIME                                │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  container.resolve(UserService)                             │
│              │                                               │
│              ▼                                               │
│  Direct new UserService(new ConsoleLogger())                │
│                                                              │
│  ✅ No reflection                                            │
│  ✅ No container lookup                                      │
│  ✅ Just function calls                                      │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Next Steps

Released under the MIT License.