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.

Generate purely typescript interfaces / plain JSON representation

See original GitHub issue

Unfortunately, discussions aren’t available for this repo and i’m not sure if this feature is out of scope or not.

Basically, I noticed that for large protocols, protobuf bundle size can go to upwards of 50kB. Considering that JSON serialization/deserialization is also accelerated by the browser’s native code, I feel like it may be more beneficial for us to use purely the JSON representation of the protobuf for RPCs.

Is it possible for protobuf-ts to support generating exclusively typescript interfaces and using JSON.parse / JSON.stringify for serialization? This could significantly lower bundle size for web apps.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
timostammcommented, Jun 7, 2021

This is actually already available! At least the core functionality. It is not documented and the API is not streamlined at all, but it works.

import { Interpreter } from '@protobuf-ts/plugin/build/interpreter';
import { DescriptorRegistry, FileDescriptorSet } from '@protobuf-ts/plugin-framework';
import { LongType, ScalarType, UnknownMessage } from '@protobuf-ts/runtime';
import { readFileSync } from 'fs';

// for the input, we need file descriptors:
// you can generate a file descriptor set with: protoc msg-scalar.proto --descriptor_set_out msg-scalar.bin
// or write them by hand in the JSON format
const buffer = readFileSync("./msg-scalar.bin");

// we need a descriptor registry:
const fileDescriptorSet = FileDescriptorSet.fromBinary(buffer);
const registry = DescriptorRegistry.createFrom(fileDescriptorSet.file[0]);

// now we create the interpreter.
// it can create message types dynamically from the descriptors in the registry.
const interpreter = new Interpreter(registry, {
    normalLongType: LongType.STRING,
    oneofKindDiscriminator: 'oneofKind',
    synthesizeEnumZeroValue: 'UNSPECIFIED$',
});


// this is how you get a dynamic message type
const fooType = interpreter.getMessageType('spec.ScalarValuesMessage');

// you can use it just like the generated messsage types,
// but of course there will be no interface for the message available.
// there is a special type for those messages, the `UnknownMessage`:
const foo: UnknownMessage = fooType.create();

// you can use reflection to work with the message
for (let field of fooType.fields) {
    console.log("field:", field.name, "value:", foo[field.localName]);
    if (field.kind === 'scalar' && field.T === ScalarType.INT32) {
        foo[field.localName] = 123;
    }
}

// you can use all message type methods:
const json = fooType.toJsonString(foo);
console.log(json)

This means it is possible to create something like proto-loader with protobuf-ts. There just needs to be a piece of code that reads proto loader json files and turns them into file descriptors.

2reactions
timostammcommented, Jun 5, 2021

I do have an idea to reduce code size further. At the moment, all functionality is packed into MessageType and can’t be shaken off if you don’t need it.

Moving the methods to standalone functions would mean that webpack output for example would not contain code for the JSON format if you only use the binary format.

This opens up several design questions though. I think this might be thing for v3…

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why you should generally prefer TypeScript interfaces and ...
If you decide to use classes to represent your data model, then you'll have to deserialize (i.e., convert) the received JSON data into...
Read more >
How We Use Our Typescript Type Information at Runtime
The JSON Schema that you'll end up with is an accurate representation of your Typescript classes, interfaces, properties, type aliases, ...
Read more >
How to Cast a JSON Object Inside of TypeScript Class
Plain objects: When we try to parse JSON data using JSON.parse() method then we get a plain object and not a class object....
Read more >
A simple guide to “interface” data type in TypeScript - Medium
An interface tells the TypeScript compiler about property names an object can have and their corresponding value types. Therefore, interface is a type...
Read more >
Documentation - Object Types - TypeScript
In JavaScript, the fundamental way that we group and pass around data is through objects. In TypeScript, we represent those through object types....
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