Skip to content

praha-inc/diva

Repository files navigation

🎵 @praha/diva

npm version npm download license Github

@praha/diva is a lightweight, type-safe dependency injection library for TypeScript. It provides a simple API for managing dependencies through context-based providers.

Installation

npm install @praha/diva

Usage

Create a context using createContext() which returns a tuple of [Resolver, Provider]:

import { createContext } from '@praha/diva';

// Create a context
const [database, withDatabase] = createContext<Database>();

// Provide a value within a scope
withDatabase(() => new Database(), () => {
  const db = database(); // Returns the Database instance
  db.query('SELECT * FROM users');
});

Transient mode

By default, providers cache the built value:

withDatabase(() => new Database(), () => {
  const db1 = database(); // New instance created
  const db2 = database(); // Same instance (cached)
  console.log(db1 === db2); // true
});

Use transient for a new instance on each resolution:

withDatabase.transient(() => new Database(), () => {
  const db1 = database(); // New instance
  const db2 = database(); // Different instance
  console.log(db1 === db2); // false
});

Curried Form

Providers support curried invocation for better reusability:

const [logger, withLogger] = createContext<Logger>();

// Create a reusable scoped function
const runWithLogger = withLogger(() => new ConsoleLogger());

runWithLogger(() => {
  logger().info('Hello, world!');
});

Optional Contexts

Create optional contexts that return undefined when not provided:

const [config, withConfig] = createContext<Config>({ required: false });

// Outside provider scope - returns undefined instead of throwing
const maybeConfig = config(); // undefined

Composing Multiple Contexts

Use withContexts() to compose multiple context providers:

import { createContext, withContexts } from '@praha/diva';

const [database, withDatabase] = createContext<Database>();
const [logger, withLogger] = createContext<Logger>();
const [auth, withAuth] = createContext<Auth>();

withContexts([
  withDatabase(() => new Database()),
  withLogger(() => new Logger()),
  withAuth(() => new Auth()),
], () => {
  // All contexts are available here
});

Testing with Mocks

Use mockContext from @praha/diva/test to inject mock values in tests:

import { createContext } from '@praha/diva';
import { mockContext } from '@praha/diva/test';

const [database, withDatabase] = createContext<Database>();

// Set up a scoped mock
mockContext(withDatabase, () => new MockDatabase());

// Now resolver returns mock without needing a provider
const db = database(); // Returns MockDatabase instance

// Transient mocks create new instances each time
mockContext.transient(withDatabase, () => new MockDatabase());
const db1 = database(); // New instance
const db2 = database(); // Different instance

🤝 Contributing

Contributions, issues and feature requests are welcome.

Feel free to check issues page if you want to contribute.

📝 License

Copyright © PrAha, Inc.

This project is MIT licensed.

About

Diva, short for “Dependency Injection Value,” is a lightweight and type-safe DI library designed for TypeScript.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors