A functional, immutable, type safe and simple dependency injection library inspired by angular.

Overview

func-di

English | 简体中文


Auto Test CI Publish CI npm version

A functional, immutable, type safe and simple dependency injection library inspired by Angular.

Why func-di

  • 0 dependency: extremely lightweight
  • functional: no class and decorator
  • immutable: stable dependency if you do not dynamically switch the whole ioc container
  • type safe: good develop experience and static type checks

Installation

For Node.JS tool chains:

npm install func-di # or other package manager

Or no tool chain:

<script type="module">
  import { token, inject, container } from "https://unpkg.com/func-di"; // or other CDN URL
  // Support ES module out of the box
</script>

Usage

See test cases for more details.

TypeScript

import { token, inject, factory, implementation, container, provide } from "func-di";
// 0. Define dependency types with interface/type:
interface ServiceA {
  foo(): number;
}

interface ServiceB {
  bar: string;
}
// 1. Define dependencies with interface/type:
const dependencyA = token<ServiceA>("ServiceA");
const dependencyB = token<ServiceB>("ServiceB");

// 2. Implement the dependencies:

// Implement a dependency factory without other dependency:
const serviceAImpl = factory(dependencyA, () => {
  return {
    foo() {
      return 111;
    },
  };
});
// Or implement a dependency factory with other injected dependency:
const serviceBImpl = inject({
  serviceA: dependencyA,
}).implements(dependencyB, ({ serviceA }) => {
  return {
    bar: serviceA.foo().toFixed(2),
  };
});
// Or implement a dependency with a direct instance:
const serviceBDirectImpl = implementation(dependencyB, { bar: "777" });

// 3. Create IOC container with service providers:

const iocContainer = container([
  // Use `stateful` if you want to cache the instance.
  // Use `stateless` if you want to create instance on every request.
  provide.stateful(serviceAImpl),
  provide.stateful(serviceBImpl),
]);

// 4. Get implementation from the container:
const serviceB = iocContainer.request(dependencyB);
console.log(serviceB.bar); // 111.00

// 5. You can create child containers to overwrite some dependency implementaions.

const childContainer = iocContainer.fork([provide.stateful(serviceBDirectImpl)]);

console.log(childContainer.request(dependencyB).bar); // 777

JavaScript

If you are using JavaScript with TypeScript language service (using vscode, Web Storm or other editor and installed func-di via Node.JS tool chain), you can pass a default instance to token for type inference.

// @ts-check
// ^^^^^^^^^ Use this directive to enable TypeScript checks in JavaScript code.
import { token, inject, factory, implementation, container, provide } from "func-di";
// 1. Define dependencies with default implementation. Types will be inferred automatically.
const dependencyA = token("ServiceA", {
  /**
   * Use type annotation in `JSDoc` comment for concrete types.
   * In this example, TypeScript will infer return type as `0` without this type annotation.
   * @returns {number}
   */
  foo() {
    return 0;
  },
});
const dependencyB = token("ServiceB", { bar: "" });

// The next steps are the same with the TypeScript example.

You can also annotate your dependency token with generic type Token in this way (not recommended, use TypeScript directly instead):

// @ts-check
// ^^^^^^^^^ Use this directive to enable TypeScript checks in JavaScript code.
import { token, inject, factory, implementation, container, provide } from "func-di";
// 0. Define your dependency types with interface/type:
/**
 * @typedef {{
 *  foo(): number;
 * }} ServiceA
 * @typedef {{
 *  bar: string;
 * }} ServiceB
 */
// 1. Define dependencies with `JSDoc` type annotation:
/** @type {import('func-di').Token<ServiceA>} */
const dependencyA = token("ServiceA");
/** @type {import('func-di').Token<ServiceB>} */
const dependencyB = token("ServiceB");

// The next steps are the same with the TypeScript example.

React Support

You can use these APIs to connect func-di with React components. Use Inject to create consumer components and Provide to create provider components.

Using Inject does not create nested HOCs. Your render function and dependency injection will be executed within the same component's render logic.

Using Provide will create a nested component. It has only one IoCContext.Provider element inside and provides the corresponding container as value.

// Relevant dependency declarations and implementations
import React from "react"
import ReactDOM from "react-dom/client";
import { Inject, Provide } from "func-di/react";
interface CountService {
  count: number;
}
interface MessageService {
  renderMessage(tag: string): React.ReactElement;
}
const countService = token<CountService>("count");
const rootCountImpl = implementation(countService, { count: 6 });
const messageService = token<MessageService>("message");
const msgImpl = inject({ countService }).implements(messageService, ({ countService }) => {
  return {
    renderMessage(tag) {
      return (
        <div>
          <span>{tag}</span>
          <span>{countService.count}</span>
        </div>
      );
    },
  };
});

// Create a consumer component
const CountMessage = Inject({ countService, messageService })
  .props<{ tag: string }>()
  .composed.fc(({ messageService, tag }) => messageService.renderMessage(tag));

// Create a provider component
const RootIoC = Provide([provide.stateful(rootCountImpl), provide.stateful(msgImpl)]).dependent();

// Use
ReactDOM.createRoot(document.querySelector('#root')!).render(
  <RootIoC>
    <CountMessage tag="foo" />
  </RootIoC>
)

License

 __________________
< The MIT license! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
You might also like...

A low-feature, dependency-free and performant test runner inspired by Rust and Deno

minitest A low-feature, dependency-free and performant test runner inspired by Rust and Deno Simplicity: Use the mt test runner with the test function

Nov 12, 2022

Cloudy is a set of constructs for the AWS Cloud Development Kit that aim to improve the DX by providing a faster and type-safe code environment.

cloudy-ts These packages aren't yet published on npm. This is still highly experimental. Need to figure out a few things before releasing the first ve

Nov 3, 2022

A script that combines a folder of SVG files into a single sprites file and generates type definitions for safe usage.

remix-sprites-example A script that combines a folder of .svg files into a single sprites.svg file and type definitions for safe usage. Technical Over

Nov 9, 2022

A fully type-safe and lightweight way of using exceptions instead of throwing errors

🛡️ exceptionally A fully type-safe and lightweight way of using exceptions instead of throwing errors 🦺 fully typesafe 🐤 lightweight (209 bytes) 🏃

Jan 4, 2023

A utility for creating toggleable items with JavaScript. Inspired by bootstrap's toggle utility. Implemented in vanillaJS in a functional style.

LUX TOGGLE Demo: https://jesschampion.github.io/lux-toggle/ A utility for creating toggleable dom elements with JavaScript. Inspired by bootstrap's to

Oct 3, 2020

Build type-safe web apps with PureScript.

Build type-safe web apps with PureScript.

PUX Build type-safe web applications with PureScript. Documentation | Examples | Chat Pux is a PureScript library for building web applications. Inter

Jun 18, 2022

Type Safe Object Notation & Validation

tson Type Safe Object Notation & Validation 📌 Work in Progress, not ready for production... Features 🧱 Functional 🔷 Immutable ✅ Well tested Why? Af

Aug 10, 2022

Zero runtime type-safe CSS in the same file as components

macaron comptime-css is now called macaron! macaron is a zero-runtime and type-safe CSS-in-JS library made with performance in mind Powered by vanilla

Jan 4, 2023

A next-gen framework for type-safe command-line applications

Zors 🥇 Next-gen framework for building modern, type-safe command-line applications. 📦 Tiny (zero dependencies) 💡 Runtime agonistic (supports both D

Dec 1, 2022
Owner
俺だって、本物が欲しい。
null
This is another Express + TypeScript + DDD (Domain Driven Design patterns) + IoC/DI (Inversion of control and Dependency injection) + Primsa ORM + API REST boilerplate.

Express-TS-DDD REST API This is another Express + TypeScript + DDD (Domain Driven Design patterns) + IoC/DI (Inversion of control and Dependency injec

J.D. 6 Nov 3, 2022
A simpliest DI(Dependency Injection) example

di-example A simpliest DI(Dependency Injection) example showing how dependency injection actually works. How to Run Install dependency with your favor

Kelly 4 Dec 6, 2022
A zero-dependency, buildless, terse, and type-safe way to write HTML in JavaScript.

hdot A sensible way to write HTML in JavaScript. Type-safe. Helps you follow the HTML spec. Terse. Almost character for character with plain HTML. Bui

Will Martin 31 Oct 24, 2022
100% type-safe query builder for node-postgres :: Generated types, call any function, tree-shakable, implicit type casts, and more

⚠️ This library is currently in alpha. Contributors wanted! tusken Postgres client from a galaxy far, far away. your database is the source-of-truth f

alloc 54 Dec 29, 2022
Functional Programming with NestJS, Prisma. immutable, pure, stateless

Functional-NestJS Functional Programming with NestJS, Prisma. immutable, pure, stateless. 1. Introduction A production ready typescript backend reposi

y0on2q 40 Dec 6, 2022
A fully type-safe and lightweight internationalization library for all your TypeScript and JavaScript projects.

?? typesafe-i18n A fully type-safe and lightweight internationalization library for all your TypeScript and JavaScript projects. Advantages ?? lightwe

Hofer Ivan 1.3k Jan 4, 2023
Type safe library for interacting with Mindbody's Public API (v6) and Webhooks

Mindbody API Type safe library for interacting with Mindbody's Public API (v6) and Webhooks ⚠️ Read before installing This library is typed according

SplitPass 4 Dec 9, 2022
Test for client-side script injection via NFTs

Rektosaurus A test suite to check for client-side script injection via NFTs. Overview NFTs contain a variety of metadata and content that gets process

Bernhard Mueller 42 Jun 28, 2022
GPU Drops' captcha solving extension without affiliate tracking code injection

Noptcha, without affiliate link injection Noptcha is a reCaptcha and hCaptcha solving extension created by GPU Drops. This fork was made because I hat

Sqaaakoi 201 Dec 26, 2022
TypeScript Transformer for injection-js

TypeScript Transformer for injection-js TypeScript Transformer for injection-js, inspired by angular-cli. Why need this No more emitDecoratorMetadata

Yadong Xie 13 Dec 4, 2022