minimal DI container in TypeScript
Rasmus Schultz

Rasmus Schultz @mindplay

About: Passionate web-developer since 1998 using various languages, databases and tools. Opinions all my own.

Joined:
Dec 25, 2017

minimal DI container in TypeScript

Publish Date: Jul 4 '18
13 2

I tried to come up with the simplest possible, useful, async DI container I could think of, and here's the result:

function Container(provider) {
    const cache = {};

    const container = function (name) {
        if (!cache[name]) {
            cache[name] = provider[name](container);
        }

        return cache[name];
    }

    return container;
}
Enter fullscreen mode Exit fullscreen mode

Totally trivial - you provide an object (provider) where each property is a function that receives the container and returns a Promise that resolves to a service.

Here's a simple use-case:

class UserCache { }

class UserService {
    constructor(private cache: UserCache) { }
}
Enter fullscreen mode Exit fullscreen mode

And usage:

const container = Container({
    "cache": async c => new UserCache(),
    "user-service": async c => new UserService(await c("cache"))
});

// and a simple test:

container("user-service").then(service => {
    console.log(service);

    container("user-service").then(same_service => {
        console.log(service === same_service); // true
    });
});
Enter fullscreen mode Exit fullscreen mode

You can try it here.

This is actually surprisingly powerful - for example, you can bootstrap multiple service-providers like this:

const container = Container({
    ...UserServices,
    ...WebServices,
});
Enter fullscreen mode Exit fullscreen mode

What I can't figure out, is how to make it type-safe - I know I'll need generics and keyof, but I could really use some help in this area.

Any takers? :-)

Comments 2 total

  • Rasmus Schultz
    Rasmus SchultzJul 4, 2018

    It's checking the keys - so far so good:

    function Container<P extends { [name: string]: { (c: any): Promise<any> } }>(provider: P) {
        const cache: { [name in keyof P]?: Promise<any> } = {};
    
        const container = function(name: keyof P) {
            if (!cache[name]) {
                cache[name] = provider[name](container);
            }
    
            return cache[name];
        }
    
        return container;
    }
    

    Now to figure out the generic return-type...

  • Rasmus Schultz
    Rasmus SchultzJul 5, 2018

    Someone has been helpful on StackOverflow already - it's partially type-hinted now!

    stackoverflow.com/questions/511764...

Add comment