Skip to content

tompston/gut

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

25 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gut

Convert Golang structs to Typescript interfaces

Handle

  • json tags, like omitempty and inline appropriately
  • uuid.UUID & time.Time conversion
  • type generation for arrays
  • setting custom names for the generated typescript interfaces
  • types which use generics (see examples/5-generic-struct)

Install

go get github.com/tompston/gut

Example

main.goexample.gen.ts
package main

import (
	"fmt"
	"time"
	"github.com/google/uuid"
	"github.com/tompston/gut"
)

func main() {

	// define which structs you want to convert
	ex1 := gut.Convert(User{})
	ex2 := gut.Convert(Comments{})
	ex3 := gut.Convert(MyRandomStruct{})

	// concat all of the interfaces together
	interfaces := fmt.Sprintln(ex1, ex2, ex3)

	if err := gut.Generate("./example.gen.ts",interfaces); err != nil {
		fmt.Println(err)
	}
}

type User struct {
	ID        uuid.UUID `json:"user_id"`
	Username  string    `json:"username"`
	CreatedAt time.Time `json:"created_at"`
	Comments  `json:"comments,omitempty"`
}

type Comments []struct {
	ID    int    `json:"comment_id"`
	Value string `json:"value"`
}

type MyRandomStruct struct {
	MyFloat     float64
	MyInterface interface{}
	Ex1         map[string]map[string]string
	IntArray    []int
}
export type UuidType = string;
export type BigIntType = BigInt;
export type DateType = Date;

export interface User {
  user_id: UuidType;
  username: string;
  created_at: DateType;
  comments?: {
    comment_id: number;
    value: string;
  }[];
}

export type CommentsArray = Comments[];

export interface Comments {
  comment_id: number;
  value: string;
}

export interface MyRandomStruct {
  MyFloat: number;
  MyInterface: any;
  Ex1: { [key: string]: { [key: string]: string } };
  IntArray: number[];
}

To format the generated typescript code, you can run deno fmt .

Why?

I wanted to solve the problem of converting golang structs to typescript interfaces, so that the backend and frontend clients could be in-sync, but I found that the current packages which try to do this had bugs and did not have the features I wanted. So I had to write it from scratch (with some help from ChatGPT)

Test

go test . -v -count=1

Features

  • Handle cases when the convertable struct is an array

  • Handle json ",omitempty" tags

  • Handle json ",inline" tags (embeded structs)

    • If a struct has a field with an json ",inline" tag, then the generated typescript interface will have all of the fields from the embeded struct inside of it. (see examples/4-struct-with-inline)
  • handle uuid.UUID & time.Time conversion

  • Avoid duplicate interface names, by generating only one typescript interface which will hold all of the types that are present in the struct.

  • Flexible typescript type system for the converted time.Time, uuid.UUID and int64 / uint64 types.

  • optionally generate the type which holds an array of interfaces

  • Ability to optionally rename the generated typescript interface to a custom name

  • flexibility in exporting the converted go structs from packages

    • Convert() returns a string which holds the generated typescript interface, thus grouping the structs from multiple packages, concatenating them together and then saving them to a single file is quite trivial.
  • Keep the package simple.

    • gut exports only 2 funtions
      • Convert() -> converts the struct into a ts string
      • Generate() -> save the converted ts interfaces to a file + define the settings for the types

Disclaimer

  • The generated TS code is not formatted. Maybe I'll fix this later. The current way to format can be done by using deno fmt .
  • There might be bugs.

Credits

The initial draft of the code was generated by ChatGPT. After some heavy refactoring, this is the end result.

Example 2 - Modify interface names + array types

main.goexample.gen.ts
package main

import (
	"fmt"
	"time"
	"github.com/google/uuid"
	"github.com/tompston/gut"
)

func main() {

	// Insetad of generating an interface called User,
	// create one with a custom name
	ex1 := gut.Convert(User{},
		gut.Type{Name: "MyCustomInterface"})

	// Generate both the interface for the struct and
	// also a type which holds an array of interfaces.
	// + optionally you can also rename it.
	ex2 := gut.Convert(MyRandomStruct{},
		gut.Type{IsArray: true, ArrayTypeName: "ArrayOfMyRandomStructs"})

	// concat all of the interfaces together
	interfaces := fmt.Sprintln(ex1, ex2)

	if err := gut.Generate("./example.gen.ts", interfaces); err != nil {
		fmt.Println(err)
	}
}

type User struct {
	ID        uuid.UUID `json:"user_id"`
	Username  string    `json:"username"`
	CreatedAt time.Time `json:"created_at"`
	Comments  `json:"comments,omitempty"`
}

type Comments []struct {
	ID    int    `json:"comment_id"`
	Value string `json:"value"`
}

type MyRandomStruct struct {
	MyFloat             float64
	MyInterface         interface{}
	Ex1                 map[string]map[string]string `json:"ex_1"`
	IntArray            []int                        `json:"int_array"`
	OptionalStringArray []string                     `json:"opt_str_array,omitempty"`
}
export type UuidType = string;
export type BigIntType = BigInt;
export type DateType = Date;

export interface MyCustomInterface {
  user_id: UuidType;
  username: string;
  created_at: DateType;
  comments?: {
    comment_id: number;
    value: string;
  }[];
}

export type ArrayOfMyRandomStructs = MyRandomStruct[];

export interface MyRandomStruct {
  MyFloat: number;
  MyInterface: any;
  ex_1: { [key: string]: { [key: string]: string } };
  int_array: number[];
  opt_str_array?: string[];
}

Example 3 - Change the predefined typescript type values

main.goexample.gen.ts
package main

import (
	"fmt"
	"time"
	"github.com/google/uuid"
	"github.com/tompston/gut"
)

func main() {

	// Insetad of generating an interface called User,
	// create one with a custom name
	ex1 := gut.Convert(User{},
		gut.Type{Name: "MyCustomInterface"})

	if err := gut.Generate(
		"./example.gen.ts", ex1, gut.Settings{
			FirstLine:  "// This is a custom comment in the file\n",
			DateType:   "string",
			UuidType:   "string",
			BigIntType: "number",
		}); err != nil {
		fmt.Println(err)
	}
}

type User struct {
	ID        uuid.UUID `json:"user_id"`
	Username  string    `json:"username"`
	CreatedAt time.Time `json:"created_at"`
}
// This is a custom comment in the file
export type UuidType = string;
export type BigIntType = number;
export type DateType = string;

export interface MyCustomInterface {
  user_id: UuidType;
  username: string;
  created_at: DateType;
}

About

Convert Golang structs to Typescript interfaces

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages