Home > Net >  Discriminate type of slice of Node.js Buffer in TypeScript
Discriminate type of slice of Node.js Buffer in TypeScript

Time:01-04

I have defined these interfaces in typescript:

enum TypeId {
  A = 0
  B = 1
  C = 2
}

interface A {
  id: TypeId.A
}

interface B {
  id: TypeId.B
  foo: string
}

interface C {
  id: TypeId.C
}

type MyType = A | B | C

Now I want to unserialize these types from a Buffer instance. I read one byte to get the ID and if it matches TypeId.B, 4 bytes have to be read for the value of foo.

How can I do this in a function with the signature parse(buffer: Buffer): MyType?

Thanks for any help.

CodePudding user response:

I infer that the Buffer to which you refer is the one from Node.js.

This is how you can parse binary data in Node: (specifically, in your case) an integer, optionally followed by a UTF-8 string:

./src/index.ts:

import {TextDecoder, TextEncoder} from 'util';

enum Id {
  A = 0,
  B = 1,
  C = 2,
}

interface A {
  id: Id.A;
}

interface B {
  id: Id.B;
  foo: string
}

interface C {
  id: Id.C;
}

type MyType = A | B | C;

export function parse (buf: Buffer): MyType {
  const id = buf.readUInt8(0);
  if (![Id.A, Id.B, Id.C].includes(id)) throw new Error('Invalid ID');
  if (id === Id.B) {
    // equivalent:
    // const foo = buf.slice(1, 5).toString('utf-8');
    const foo = new TextDecoder().decode(buf.slice(1, 5));
    return {id, foo};
  }
  return {id};
}

function main () {
  // equivalent:
  // const buf0 = Buffer.from([0, ...Buffer.from('hello', 'utf-8')]);
  const encoder = new TextEncoder();
  const buf0 = Buffer.from([0, ...encoder.encode('hello')]);
  const buf1 = Buffer.from([1, ...encoder.encode('example string')]);
  const buf2 = Buffer.from([2, ...encoder.encode('another one')]);

  console.log(parse(buf0)); // { id: 0 }
  console.log(parse(buf1)); // { id: 1, foo: 'exam' }
  console.log(parse(buf2)); // { id: 2 }
}

main();

For reference, this is the TSConfig I used:

{
  "compilerOptions": {
    "exactOptionalPropertyTypes": true,
    "isolatedModules": true,
    "lib": [
      "ESNext"
    ],
    "module": "ESNext",
    "moduleResolution": "Node",
    "noUncheckedIndexedAccess": true,
    "outDir": "dist",
    "strict": true,
    "target": "ESNext",
  },
  "include": [
    "./src/**/*"
  ]
}
  •  Tags:  
  • Related