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/**/*" ] }