Tag Archives: backpack.tf websocket

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!