Skip to content

octavore/pbts

Repository files navigation

pbts

pbts is a simple pb.go to .ts converter. It converts the protoc generated Golang definitions for protobuf messages into a Typescript abstract class.

The motivation for pbts is to be able to easily -

  1. define APIs using protobufs,
  2. implement the API server using Golang, and
  3. implement frontend client in Typescript.

The types generated by protoc and pbts respectively will ensure that (<pedantic>some</pedantic>) breaking API changes will cause compile time errors.

Notes

  • a copy function is generated to copy data between instances.
  • following protobuf conventions, int64 types are serialized as strings.
  • proto maps and oneofs are supported
  • the types generated will be satisfied by json generated with protojson.MarshalOption{EmitDefaultValues: true}

Example Usage

# main.go

writer, _ := os.OpenFile("api.ts", ...)
g := pbts.NewGenerator(writer)
g.RegisterMany(
  &MyFirstStruct{},
  &MySecondStruct{},
)
g.Write()

Example Output

Import the generated classes into your Typescript project for fun and profit.

type TestStruct struct {
	Field      *string           `protobuf:"bytes,1,opt,name=field" json:"field,omitempty"`
	FieldInt   *int64            `protobuf:"varint,6,opt,name=field_int,json=fieldInt" json:"field_int,omitempty"`
	Metadata   map[string]int32  `protobuf:"bytes,11,rep,name=metadata" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
	Tags       []string          `protobuf:"bytes,12,rep,name=tags" json:"tags,omitempty"`
}
# api.ts

export abstract class MyFirstStruct {
  field?: string;
  fieldInt?: string;
  metadata: { [key: string]: number; };
  tags: string[];
  static copy(from: MyFirstStruct, to?: MyFirstStruct): MyFirstStruct {
    if (to) {
      to.field = from.field;
      to.fieldInt = from.fieldInt;
      to.metadata = from.metadata;
      to.tags = from.tags;
      return to;
    }
    return {...from};
  }
}

...

Enums

pbts supports two enum modes: native enums and string literal types:

Default:

export type TestEnum = 'bar' | 'foo' | 'unknown';

By setting g.NativeEnums = true:

export enum TestEnum {
  Bar = "bar",
  Foo = "foo",
  Unknown = "unknown",
}