Generate TypeScript interfaces from Go structs/interfaces - useful for JSON RPC
bel
is used in production in https://gitpod.io.
bel
is easy to use. There are two steps involved: extract the Typescript information, and generate the Typescript code.
package main
import (
"github.com/32leaves/bel"
)
type Demo struct {
Foo string `json:"foo,omitempty"`
Bar uint32
Baz struct {
FirstField bool
SecondField *string
}
}
func main() {
ts, err := bel.Extract(Demo{})
if err != nil {
panic(err)
}
err = bel.Render(ts)
if err != nil {
panic(err)
}
}
produces something akin to (sans formatting):
export interface Demo {
foo?: string
Bar: number
Baz: {
FirstField: boolean
SecondField: string
}
}
You can also convert Golang interfaces to TypeScript interfaces. This is particularly handy for JSON RPC:
package main
import (
"os"
"github.com/32leaves/bel"
)
type DemoService interface {
SayHello(name, msg string) (string, error)
}
func main() {
ts, err := bel.Extract((*DemoService)(nil))
if err != nil {
panic(err)
}
err = bel.Render(ts)
if err != nil {
panic(err)
}
}
produces something akin to (sans formatting):
export interface DemoService {
SayHello(arg0: string, arg1: string): string
}
You can try all the examples mentioned below in Gitpod.
Follow structs enable the transitive generation of types. See examples/embed-structs.go.
would produce code for the interface UserService
, as well as the struct it refers to AddUserRequest
, and User
because it's referenced by AddUserRequest
.
Without FollowStructs
we'd simply refer to the types by name, but would not generate code for them.
SortAlphabetically sorts all types and their members by alphabetical order. This produces more deterministic/stable output, which is great for making things comparable across pull requests. See examples/sort-alphabetically.go.
Embed structs is similar to FollowStructs
except that it produces a single canonical type for each structure.
Whenever one struct references another, that reference is resolved and the definition of the other is embedded.
See examples/embed-structs.go.
NameAnonStructs
is kind of the opposite of EmbedStructs
. When we encounter a nested anonymous struct, we make give this previously anonymous structure a name and refer to it using this name.
See examples/name-anon-structs.go.
CustomNamer
enables full control over the TypeScript type names. This is handy to enforce a custom coding guideline, or to add a prefix/suffix to the generated type names.
See examples/custom-namer.go.
See examples/enums.go.
Go famously does not have enums, but rather type aliases and consts. Using reflection alone there is no way to obtain a comprehensive list of type values, as the linker might optimize and remove some. bel supports the extraction of enums by parsing the Go source code. Note that this is merely a heuristic and may fail in your case. If it does not work, bel falls back to the underlying type.
Enums can be generated as TypeScript enum
or as sum types. Use the bel.GenerateEnumsAsSumTypes
flag to change this behaviour.
See examples/code-generation.go.
When generating the TypeScript code you might want to wrap everything in a namespace. To that end bel.GenerateNamespace("myNamespaceName")
can be used.
By default bel adds a comment to the files it generates. You can influcence this comment (and any other code that comes before the generated code)
using bel.GeneratePreamble
and bel.GenerateAdditionalPreamble
.
You can configure the io.Writer
that bel uses using bel.GenerateOutputTo
.
All contributions/PR/issue/beer are welcome ❤️.