npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

moleculer-type-utils

v0.2.0

Published

Type Utilities for Moleculer framework to help working with it in TypeScript

Downloads

32

Readme

Moleculer Type Utils

GitHub Actions Workflow Status

NPM Version

Table of Contents

Intro Promo

So... uh... Type safety, amiright?

This and without code generation and manually writing external interfaces:

Sample 1 Sample 2

Want to call actions with automattically loaded types? With names, params, meta. Don't want to generate manually or with watcher type definitions for actions?

I got you covered. At least for Moleculer 0.14 (rumors that 0.15 version will have some types breaking changes so if you are from the future and I forgot to update this package sorry and ping me in issues or if you are brave enough fire a pull request).

What

This package contains type helpers for working with Moleculer microservice framework.

Currently these type utils help with:

  • Typed actions

Why

I don't really like the idea of generating type definitions if it's possible to obtain type safety by utilizing fantastic and powerful TypeScript type system.

In case of Moleculer it's totally possible to create helper types for writing calls to actions.

Installation

yarn add moleculer-tyle-utils --dev

or

npm install moleculer-type-utils --save-dev

or

similar with other package managers like pnpm, bun and others I don't know but they surely exist.

Usage

Ok here is the receipt:

Typed Broker

  1. Write service as usual with 1 additional step:
  import { ServiceSchema, Context } from "moleculer";

  export default {
    name: "service:alpha" as const, // IMPORTANT STEP : always add `as const` to the name
    version: 2 as const, // OPTIONAL: ONLY if you are using versions in services, always add `as const` too.
    actions: {
      alphaAction(ctx: Context<{ name: string }>) {
        return "kek";
      },
      alphaActionWithoutParamsAndMeta(ctx: Context) {
        return "value";
      },
      alphaActionWithoutParamsWithMeta(ctx: Context<null, { userId: string }>) {
        return 24;
      },
      alphaActionWithVoidReturn(ctx: Context) {}
    }
  } satisfies ServiceSchema;
  1. Notice satisfies ServiceSchema part. What it's for? If you want to achieve type safety when defining your service as well as IDE helpers with types - you usually write code like const a: MyType = {} or const a = {} as MyType.

    You WILL achieve type safety, but will loose the computed type of your object. And it won't work with this package. Because you are forcibly casting to some type, loosing the real implementation.

    Use satisfies instead. This way you still have type safety, but now your type can be inferred fully by TypeScript type system.

  1. Create file where you will store your typed broker. For example types/my-broker.ts.

    Here what you should write as it's contents:

      import { BetterTypedServiceBroker } from "moleculer-type-utils";
    
      type ServiceDefinitions = [
        typeof import("./my-services/service-alpha").default,
        typeof import("./my-services/service-beta").default,
      ];
    
      // Alternate way. Original may look too obnoxious for some people :D
      // import ServiceAlpha from "./my-services/service-alpha";
      // import ServiceBeta from "./my-services/service-beta";
      // type ServiceDefinitions = [typeof ServiceAlpha, typeof ServiceBeta];
    
    
      type MyBroker = BetterTypedServiceBroker<ServiceDefinitions>;

    Get types of your services and store them in tuple type. This is important. Not union, but tuple (array). Then you pass this tuple as generic to BetterTypedServiceBroker.

  1. Ok so now you have type MyBroker, which has .call method with your actions.

    Use it like this in your services:

      const result = await (broker as MyBroker).call("service.actionName", ..., ...);
      // broker will help with params and meta if they are required by your action.
    
    
      // Example with using versioned service
      const result = await (broker as MyBroker).call("v2.service.actionName", ..., ...);

Typed Context

Typed Context is a bit tricky compared to broker, because context has generics. So to leave original functionality of Context intact, we need to do like this (in types/my-context.ts for example):

  // We need this for default GenericObject generic
  import { GenericObject } from "moleculer";
  import { BetterTypedContext } from "moleculer-type-utils";

  // As in Typed Broker manual step 3, you need to obtain your service definitions.

  type TestContext<P = unknown, M extends object = {}, L = GenericObject> = BetterTypedContext<ServiceDefinitions, P, M, L>;

Use it like this in your services:

  // Assuming this code inside service action.

  const result = await (ctx as TestContext).call("service.actionName", ..., ...);

  // Or if you want to use only typed context.

  const myCtx = ctx as TestContext<YourParams, YourMeta>;

  // After passing generics you have typed params, meta
  myCtx.params.myParam;

  await myCtx.call("service.actionName", ..., ...);

Typed Context as argument type in service definition (currently NOT POSSIBLE)

The IDEAL easy way to use typed context, of course, would be this:

  export default {
    name: "service:delta" as const,
    actions: {
      deltaAction(ctx: TypedContext<{ version: string }>) {
        
        // A man can dream that this would work one day...
        ctx.call("myAnotherService.actionName", { params: 2 }, { user: 3 });

        return {
          something: 34
        };
      },
      deltaActionWithObjectDefinition: {
        handler(ctx: TypedContext<{ myParam: number }, { log: boolean }>) {
          return { name: "object" };
        }
      }
    }
  };

With code like this we would have typed context at the tip of out fingers.

THE PROBLEM. Why we still need to const typedBroker = broker as TypedBroker;

Circular reference in TypeScript. We are facing the problem, when TypedContext would consume definition of services, which are using... TypedContext as argument. Well, this is a circular reference and currently I am working on an easy way to overcome this problem and make it easier to use typed context directly as argument type. Maybe in future updates it would be possible.

Changelog

[0.2.0] - 2024-04-27

  • Typed context (instructions updated how to use it)
  • Support for service versions (if version is defined in service definition). Thanks https://github.com/adelisle for PR!

[0.1.0] - 2024-03-15

  • Initial repo. Features type for broker, that helps with action typings