question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TypeScript interface is incomplete

See original GitHub issue

In particular, ParserOptions does implement all available options (e.g., length can be a string or function too).

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:1
  • Comments:7 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
wpyogacommented, Sep 6, 2022

This is a very nice feature to have. It is not impossible to implement – data validation libraries have been doing this for quite some time. However, I have been reading Zod’s source code (looks like very advanced stuff), but I haven’t yet figured out a way to recreate the same effect. Also, there are other validation libraries, it’s just that Zod is the one I’m most familiar with.

See below for an example using Zod, using the IPv4 header parsing example.

Notes:

  1. parsedIpHeader is the any object parsed by binary-parser.
  2. validatedIpHeader, validatedIpHeaderV2, and validatedIpHeaderV3 are the type-inferred objects validated by zod.
  3. The method-chaining approach takes up a lot of cpu resources to process. I think it’s not impossible to implement in binary-parser, and maybe we can have something like
    Parser.start()
    .uint32be("id")
    ... 
    .uint8("checksum")
    .end()
    
    Where end() marks the end of the call chain, and it’s the only place where the parser types are inferred.
  4. In VS Code, I get this type hint for validatedIpHeader:
    const validatedIpHeader: {
        version: number;
        headerLength: number;
        tos: number;
        packetLength: number;
        id: number;
        offset: number;
        fragOffset: number;
        ttl: number;
        protocol: number;
        checksum: number;
        src: number[];
        dst: number[];
    }
    
Example (long block of code)

// Module import
const Parser = require('binary-parser').Parser;

// Alternative way to import the module
// import { Parser } from 'binary-parser';

// Build an IP packet header Parser
const ipHeader = new Parser()
  .endianness('big')
  .bit4('version')
  .bit4('headerLength')
  .uint8('tos')
  .uint16('packetLength')
  .uint16('id')
  .bit3('offset')
  .bit13('fragOffset')
  .uint8('ttl')
  .uint8('protocol')
  .uint16('checksum')
  .array('src', {
    type: 'uint8',
    length: 4,
  })
  .array('dst', {
    type: 'uint8',
    length: 4,
  });

// Prepare buffer to parse.
const buf = Buffer.from('450002c5939900002c06ef98adc24f6c850186d1', 'hex');

// Parse buffer and show result
console.log(ipHeader.parse(buf));

// preparation

import { z } from 'zod';
const parsedIpHeader = ipHeader.parse(buf);

// typical Zod usage

const ipHeaderValidator = z.object({
  version: z.number(),
  headerLength: z.number(),
  tos: z.number(),
  packetLength: z.number(),
  id: z.number(),
  offset: z.number(),
  fragOffset: z.number(),
  ttl: z.number(),
  protocol: z.number(),
  checksum: z.number(),
  src: z.array(z.number()).length(4),
  dst: z.array(z.number()).length(4),
});

const validatedIpHeader = ipHeaderValidator.parse(parsedIpHeader);

console.log(validatedIpHeader);

// chained -- non-typical, vscode takes a long time processing this

const ipHeaderValidatorV2 = z
  .object({})
  .extend({ version: z.number() })
  .extend({ headerLength: z.number() })
  .extend({ tos: z.number() })
  .extend({ packetLength: z.number() })
  .extend({ id: z.number() })
  .extend({ offset: z.number() })
  .extend({ fragOffset: z.number() })
  .extend({ ttl: z.number() })
  .extend({ protocol: z.number() })
  // .extend({ checksum: z.number() })
  // .extend({ src: z.array(z.number()).length(4) })
  // .extend({ dst: z.array(z.number()).length(4) });
  // if the last 3 properties are uncommented, tsc will emit an error:
  // error TS2589: Type instantiation is excessively deep and possibly infinite.

const validatedIpHeaderV2 = ipHeaderValidatorV2.parse(parsedIpHeader);

console.log(validatedIpHeaderV2);

// this works, but type hint is delayed, and vscode hogs cpu processing this

const ipHeaderValidatorV3 = z
  .object({})
  .merge(z.object({ version: z.number() }))
  .merge(z.object({ headerLength: z.number() }))
  .merge(z.object({ tos: z.number() }))
  .merge(z.object({ packetLength: z.number() }))
  .merge(z.object({ id: z.number() }))
  .merge(z.object({ offset: z.number() }))
  .merge(z.object({ fragOffset: z.number() }))
  .merge(z.object({ ttl: z.number() }))
  .merge(z.object({ protocol: z.number() }))
  .merge(z.object({ checksum: z.number() }))
  .merge(z.object({ src: z.array(z.number()).length(4) }))
  .merge(z.object({ dst: z.array(z.number()).length(4) }));

const validatedIpHeaderV3 = ipHeaderValidatorV3.parse(parsedIpHeader);

console.log(validatedIpHeaderV3);

0reactions
keichicommented, Jul 3, 2022

@cmdcolin Yes, it is expected but a type-safe interface would be very cool. Do you have any good ideas on how to implement it?

Read more comments on GitHub >

github_iconTop Results From Across the Web

typescript - How to use incomplete types - Stack Overflow
I would like to use T as the type for the properties parameter since it has the type information I want already, but...
Read more >
Can wrongly assign object with incomplete mapped type to ...
Based on how this applies to interfaces but not type aliases, I'd guess this is a bug with interface type parameter variance probing....
Read more >
Documentation - Utility Types - TypeScript
Partial <Type> ... Constructs a type with all properties of Type set to optional. This utility will return a type that represents all...
Read more >
Intellij creates incomplete method on "Implement all members ...
The bundled "JavaScript and TypeScript" repeatedly generates incorrect ... For instance, I've got this method defined in an interface:
Read more >
No More Confusion About TypeScript's Type and Interface
TypeScript type vs interface, Types vs interfaces in TypeScript, TypeScript type, TypeScript interface, difference between interface and type.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found