Dependency Injection

Sometimes you would like to separate routes from your main file.

Normally you would decouple them into a plugin like:

// index.ts
const app = new Teasim().use(authenRoute).use(profileRoute);
// and so on...

// routes/authen.ts
const authen = new Teasim().post("/sign-in", signIn).post("/sign-up", signUp);

You might want to introduce some state, and decorate in the main instance that you actually need in a separated module.

// index.ts
const app = new Teasim().decorate("signOut", signOut).state("redis", redis).use(authenRoute).use(profileRoute);
// and so on...

// routes/authen.ts
const authen = new Teasim()
  .post("/sign-in", signIn)
  .post("/sign-up", signUp)
  // But then there is no type
  .post("/sign-out", ({ signOut, store: { redis } }) => {
    signOut();

    redis.doSomething();
  });

If you hover over the main app in index.ts, you can see the auto-generated type for your main server which might look something like this:

const app: Teasim<
  "",
  {
    store: {
      redis: Redis;
    };
    request: {
      signOut: () => void;
    };
    schema: {};
  }
>;

But this type isn't applied to sub-modules.

To apply the type to sub-modules, you can create a plugin which only contains state and decorate which causes type side-effect as a dependency, and applies it to any sub-modules you want.

const setup = new Teasim({ name: "setup" }).decorate("signOut", signOut).state("redis", redis);

// routes/authen.ts
const authen = new Teasim()
  .use(setup)
  .post("/sign-in", signIn)
  .post("/sign-up", signUp)
  // Now it's strictly typed
  .post("/sign-out", ({ signOut, store: { redis } }) => {
    signOut();

    redis.doSomething();
  });

This will allow you to control access to decorators in modules. This concept is also known as Dependency Injection but only for types.