Publishing Software

I published two pieces of software I had been working on recently. They are both related to consuming WebSocket and written in TypeScript.

Joe's Socket To Interface Utility
This utility is to help discover a common interface from object sent over
a WebSocket pipe.
Joe's WebSocket Manager
A simple interface to connect to a WebSocket and receive an event
when messages are pending.

The WebSocket manager has been used for some time in a side project and is very solid. The Socket To Interface Utility was a quick project I did yesterday to capture a single interface over a disparity of messages that start similar at the root but towards the leaves are very different.

I hope these are useful to someone. Enjoy!

Converting Streams of JSON Data to a Typescript Interface

If MariusAlch were on twitter, I’d @ him and say, “Thank you so much for your useful json-to-ts utility!”

Json to TS converts JSON to Typescript interfaces. It’s especially useful because it converts arrays of different sets to a unified interface. I used it to catch messages of varying payloads from Backpack.tf’s websocket and create a nice common interface for the messages. The payload are mainly homogeneous near the root of the object but it’s somewhat scattered towards the leaves. You can see from this example backpack.tf websocket payload how dense the data can be.

My utility does a deep examination of any messages’s structure and simplifies it to an abbreviated version which I called the “Shape” of the object.

type Shape = {
  [key: string]: string | null | boolean | 
                 number | Shape[]
} | string | null | boolean | number

You can see how the type is concise and sufficient for generic JSON message Interface detection. A sample of the tests are as follows.

expect(deepShape({a: "aValue"}))
        .toEqual({a: ""});
expect(deepShape({
                   a: "aValue",
                   numbers: [1,2,3]}))
       .toEqual({
                   a: "",
                   numbers: [0]});
expect(deepShape({a: true}))
        .toEqual({a: true});

While collecting messages, I take a hash of the Shape and, if I get a new sample, I add it to my collection. Once I’ve taken a sufficient sampling, the software assembles all the messages into an object that has my root type as the key and a vector to hold the samples. I pass the object to JsonToTs() and, “huzzah!”, out pops all my interfaces with optional types nicely intertwined.

const existing = 
  await fs.promises.readdir(shapePath);
const messages: {BPSocketEvent: Shape[]} =
  {BPSocketEvent: []}
for await (const file of existing) {
  const shapeFilePath =
    [shapePath,file].join(path.sep);
  const entry = 
    await fs.promises.readFile(shapeFilePath);
  messages.BPSocketEvent.push(
    JSON.parse(entry.toString())
  );
}
const interfaces = [];
for await (const typeInterface of JsonToTS(messages)) {
    interfaces.push(typeInterface);
}
console.log(interfaces.join('\n\n'));

So thank you very much MariusAlch!

Fix “ESLint: Unsafe call of an `any` typed value” using express (expressJS) and TypeScript

When trying to be diligent about keeping strict types via ESLint in a TypeScript based ExpressJS, You may hit the dreaded, “ESLint: Unsafe call of an any typed value. (@typescript-eslint/no-unsafe-call)” while trying to use the default express() method via:

import express from 'express';

const app = express();

After an npm i -D @types/express the error will remain. After searching around and seeing so many fixes for importing Request and Response types, I finally found an explanation of how to fix the any typed value error on the express() method via smichel17’s response to, “express() function and express namespace ambiguity #37920”. The nuance is in that “import” returns plain objects and “require” returns returns objects and functions. Note that you cannot destructure the “require” call so to get your “Request” and “Response” types without using “express.Request” and “express.Response” you still need the traditional import statement as well.

Update your code to the following and resolve the “Unsafe call of an any typed value” error without using the dreaded escape hatch of "noImplicitAny": false.

import express = require('express');
import { Request, Response } from 'express';

const app = express();
const port = 3000;

app.get('/', (req: Request, res: Response) => {
  res.status(200).send(
    'Express + TypeScript Server ' +
    'With Strict Types by Joe');
});

app.listen(port, () => {
  console.log(
    `⚡️[server]: Server is running ' + 
    ' at http://localhost:${port}`);
});