tygo

repository·main·Indexed 21 days ago

https://github.com/gzuidhof/tygo

A tool for generating TypeScript typings from Golang source files. Tygo supports Go 1.18+ generics, struct inheritance, and the preservation of comments. It features configurable generation styles for constants (enums or unions), YAML-serializable struct mapping via the 'flavor' option, and custom type overrides using 'tstype' tags or '//tygo:emit' directives.

Tokens
3.1K
Snippets
15
Records
16
Agent score
71%

What's inside tygo

  1. Support for Go Generics

    main

    Tygo supports Go generic types (Go 1.18+) out of the box, translating them into TypeScript generic interfaces/types.

    type UnionType interface {
    	uint64 | string
    } 
    
    type ABCD[A, B string, C UnionType, D int64 | bool] struct {
    	A A `json:"a"` 
    	B B `json:"b"` 
    	C C `json:"c"` 
    	D D `json:"d"` 
    }
  2. Implement inheritance in TypeScript types

    main

    Tygo supports interface inheritance using the tstype:",extends" tag on struct fields. Only struct types can be extended.

    • Standard Structs: Use tstype:",extends".
    • Struct Pointers: These are extended using Partial<MyType>. To make them required, use tstype:",extends,required".
    • Named Fields: You can extend named struct fields.
    • External Structs: You can extend structs from other packages.
    type Other[T int] struct {
    	*Base                  `       tstype:",extends,required"` 
    	Base2[T]               `       tstype:",extends"` 
    	*OptionalPtr           `       tstype:",extends"` 
    	external.AnotherStruct `       tstype:",extends"` 
    	OtherValue             string `                  json:"other_value"` 
    }
  3. Emit literal TypeScript code with `//tygo:emit`

    main

    For types that cannot be directly represented in Go (like complex tuples), use the //tygo:emit directive.

    Emit before a struct

    A directive placed above a struct will emit the text following it before the struct definition.

    //tygo:emit export type Genre = "novel" | "crime" | "fantasy"
    type Book struct {
    	Title    string    `json:"title"` 
    	Genre    string    `json:"genre" tstype:"Genre"` 
    }

    Emit multi-line content

    A directive on a string variable will emit the contents of that variable.

    //tygo:emit
    var _ = `export type StructAsTuple=[
      a:number,
      b:number,
      c:string,
    ]
    ` 
    
    type CustomMarshalled struct {
      Content []StructAsTuple `json:"content"` 
    }
  4. Specify TypeScript types using `tstype` tags

    main

    You can override the generated TypeScript type for a struct field using the tstype tag in Go.

    Custom Type Mapping

    Use tstype to provide a literal TypeScript type string.

    type Book struct {
    	Title    string    `json:"title"` 
    	Genre    string    `json:"genre" tstype:"'novel' | 'crime' | 'fantasy'"` 
    }

    Required Fields

    By default, pointer types in Go become optional (?) in TypeScript. To make them required, add ,required to the tag.

    type Nicknames struct {
    	Alice   *string `json:"alice"` 
    	Bob     *string `json:"bob" tstype:"BobCustomType,required"` 
    	Charlie *string `json:"charlie" tstype:",required"` 
    }

    Readonly Fields

    To make a field immutable in TypeScript, add ,readonly to the tag.

    type Cat struct {
    	Name    string `json:"name,readonly"` 
    	Owner   string `json:"owner"` 
    }

    Omit Fields

    Use tstype:"-" to omit a field from the TypeScript output.

  5. Install tygo

    main

    Install the tygo CLI tool using go install to generate TypeScript typings from Go source files.

    go install github.com/gzuidhof/tygo@latest
  6. Use tygo via CLI

    main

    The recommended way to use tygo is via the CLI. Create a tygo.yaml configuration file to specify the Go packages to convert and any custom type mappings. Then run the generate command.

    Example tygo.yaml:

    packages:
      - path: "github.com/gzuidhof/tygo/examples/bookstore"
        type_mappings:
          time.Time: "string /* RFC3339 */"
          null.String: "null | string"
          null.Bool: "null | boolean"
          uuid.UUID: "string /* uuid */"
          uuid.NullUUID: "null | string /* uuid */"

    Run the generation:

    tygo generate

    By default, the output TypeScript file is written next to the Go source files.

  7. Configure tygo via tygo.yaml

    main

    The tygo.yaml file allows for global and package-specific configuration.

    Global Configuration

    • type_mappings: A map of Go types to TypeScript type strings that applies to all packages.

    Package Configuration

    Within the packages list, you can define:

    • path: The Go package path (as used in imports).
    • output_path: Where the output should be written. If a folder is specified, it writes to index.ts within that folder.
    • indent: Custom indentation string (e.g., " " or "\t").
    • type_mappings: Package-specific mappings that override global ones.
    • frontmatter: String content injected at the top of the output file (useful for imports).
    • exclude_files: List of Go filenames to ignore.
    • extends: The TypeScript type that the generated types should extend.
    • enum_style: Controls how Go const groups are generated. Supported values: "const" (default), "enum", or "union".
    type_mappings:
      time.Time: "string /* RFC3339 */"
    
    packages:
      - path: "github.com/my/package"
        output_path: "webapp/api/types.ts"
        indent: "    "
        type_mappings:
          time.Time: "string"
          my.Type: "SomeType"
        frontmatter: |
          "import {SomeType} from "../lib/sometype.ts"
        exclude_files:
          - "private_stuff.go"
        extends: "SomeType"
        enum_style: "enum"
  8. Configure TypeScript Enum or Union generation style

    main

    Tygo can generate either native TypeScript enums or TypeScript union types from Go constant groups. This behavior is controlled by the enum_style configuration option.

    Requirements for Enum/Union Generation

    For a Go const group to be recognized, it must meet these criteria:

    1. It must contain at least 2 exported constants.
    2. All constants in the group must share the same type (e.g., UserRole).
    3. Constant names must follow a consistent prefix pattern (e.g., UserRoleDefault, UserRoleEditor).

    Generation Styles

    • enum_style: "enum": Converts matching Go constants into a TypeScript enum.
    • enum_style: "union": Converts matching Go constants into individual const declarations and a TypeScript type union.

    If a const block contains a mix of enum-like constants and other unrelated constants, Tygo will generate the enum/union for the matching group and individual const declarations for the remaining items.

    # Example configuration for enum style
    enum_style: "enum"
  9. Generate TypeScript types for YAML-serializable Go structs

    main

    Tygo can generate TypeScript interfaces that match how Go handles YAML serialization.

    By default, Tygo respects yaml Go struct tags (and json tags). However, if you want to emulate the behavior of gopkg.in/yaml.v2 where untagged struct fields are automatically downcased in the resulting YAML, you must set the flavor configuration option to "yaml".

    When flavor: "yaml" is used, untagged fields in the TypeScript output will be lowercased to match standard Go YAML behavior.

    packages:
      - path: "github.com/my/package"
        output_path: "webapp/api/types.ts"
        flavor: "yaml"
  10. Example: YAML Struct Mapping (Go to TypeScript)

    main

    This example shows how Tygo maps Go structs to TypeScript interfaces, specifically demonstrating how the flavor: "yaml" setting affects untagged fields.

    Go Input:

    type Foo struct {
    	TaggedField string `yaml:"custom_field_name_in_yaml"`
        UntaggedField string
    }

    TypeScript Output (with flavor: "yaml"):

    export interface Foo {
      custom_field_name_in_yaml: string;
      untaggedfield: string;
    }
  11. Example: String Enums (Go to TypeScript)

    main

    This example demonstrates how Tygo converts a Go string-based constant group into TypeScript using both enum and union styles.

    Go Input:

    type Status = string
    const (
        StatusActive   Status = "active"
        StatusInactive Status = "inactive"
        StatusPending  Status = "pending"
    )

    TypeScript Output (enum_style: "enum"):

    export enum Status {
      Active = "active",
      Inactive = "inactive",
      Pending = "pending",
    }

    TypeScript Output (enum_style: "union"):

    export const StatusActive = "active";
    export const StatusInactive = "inactive";
    export const StatusPending = "pending";
    export type Status = typeof StatusActive | typeof StatusInactive | typeof StatusPending;
  12. Example: Numeric Enums with iota (Go to TypeScript)

    main

    This example demonstrates how Tygo handles Go numeric constants using iota.

    Go Input:

    type Priority int
    const (
        PriorityLow Priority = iota
        PriorityMedium
        PriorityHigh
    )

    TypeScript Output (enum_style: "enum"):

    export enum Priority {
      Low = 0,
      Medium,
      High,
    }

    TypeScript Output (enum_style: "union"):

    export const PriorityLow = 0;
    export const PriorityMedium = 1;
    export const PriorityHigh = 2;
    export type Priority = typeof PriorityLow | typeof PriorityMedium | typeof PriorityHigh;