Skip to main content

Value Objects

Typically value objects will be serialized / marshalled as JSON. Please refer to this documentation:

https://pkg.go.dev/encoding/json#Marshal

This is just a few basic examples, that show the basics of mapping Go types to idiomatic TypeScript types.

Scalar types

Supported in Go and TypeScript

GoTypeScript
stringstring
boolboolean

Numerics / numbers

GoTypeScript
int, int8, int16, float32, float64 ...number

Type Aliases

type Greeting string
type Greeting = string;

Enumerations

Go does not support enumerations, but gotsrpc will translate constants to TypeScripts enums:

type Pet string

const (
    Cat Pet  = "cat"
    Dog Pet  = "dog"
    Fish Pet = "fish"
)

type SeatCount int

const (
	TwoSeats   SeatCount = 2
	FiveSeats  SeatCount = 5
	SevenSeats SeatCount = 7
)
export enum Pet {
  Cat = "cat",
  Dog = "dog",
  Fish = "fish",
}

export enum SeatCount {
  FiveSeats = 5,
  SevenSeats = 7,
  TwoSeats = 2,
}

Slices

Slices are nilable in Go, thus they can be null in TypeScript. They translate to Array<T>|null in TypeScript.

Scalar types

[]string
[]int
// other numeric types
[]bool
Array<string> | null;
Array<number> | null;
// all numeric types are numbers
Array<boolean> | null;

Other slice type examples

Structs

[]Car
[]*Car
Array<Car> | null;
Array<Car | null> | null;

Nested slices

[][]string
[][]int
// ...
Array<Array<string> | null> | null;
Array<Array<number> | null> | null;
// ...

Maps / Records

Like slices Go maps are nilable. They translate to Record<K extends keyof any, T>|null in TypeScript.

Scalars

map[string]string
Record<string, string> | null;

Structs

map[string]*Car
Record<string, Car | null> | null;

Slices

map[string][]*Car
Record<string, Array<Car | null> | null> | null;

Map types

Go and TypeScript support map / Record types:

Scalar types / type aliases are of particular value when using maps, because they can add strong semantics:

type CarDirectory map[ProductID]*Car
type CarDirectory = Record<ProductID, Car | null> | null;

Nested map types

type BrandID string
type BrandCarDirectory map[BrandID]map[ProductID]*Car
// or
type BrandCarDirectory map[BrandID]CarDirectory
type BrandID = string;
type BrandCarDirectory = Record<
  BrandID,
  Record<ProductID, Car | null> | null
> | null;
// or
type BrandCarDirectory = Record<BrandID, CarDirectory> | null;

Structs / Interfaces

Arbitrary Types can be composed in structs.

Field names

Naming conventions are different between Go and TypeScript. In order to bridge the gap between Go and TypeScript Go struct fields can be annotated with tags. In this way idiomatic naming of fields can be can be provided for both languages and the translation will be automatic.

Default Go => TypeScript

Without json tags TypeScript field names will be like in Go, which is not idiomatic for TypeScript.

type Car struct {
    GoCase string
    CamelCase string
    SnakeCase string
}
interface Car {
  GoCase:string;
  CamelCase:string;
  SnakeCase:string;
}

Idiomatic field names

Json tags allow controlling the name in TypeScript.

type Car struct {
    CamelCase string `json:"camelCase"`
    SnakeCase string `json:"snake_case"`
}
interface Car {
  camelCase:string;
  snake_case:string;
}

Optional and nullable fields

type Basic struct {
    Value string `json:"value"`
    OptionalValue string `json:"optionalValue,omitempty"`
    NullableValue *string `json:"nullableValue"`
}
type Basic interface {
    value:string;
    optionalValue?:string;
    nullableValue:string|null;
}

Hiding values from the client

The Go json tag `json:"-"` on a struct allows it to:

  • hide fields from clients
  • prevents clients from setting them in JSON Unmarshalling
type Basic struct {
    Value string `json:"value"`
    Secret string `json:"-"`
}
type Basic interface {
    value:string;
}

Union Types

When static types seem to be in the way

Scalars

type (
	Species struct {
		LandAnimals  *LandAnimals  `json:"landAnimals,omitempty" gotsrpc:"union"`
		WaterAnimals *WaterAnimals `json:"waterAnimals,omitempty" gotsrpc:"union"`
	}
	LandAnimals  string
	WaterAnimals string
	)
	
	const (
		Cat LandAnimals = "cat"
		Dog LandAnimals = "dog"
	)
	
	const (
		Catfish WaterAnimals = "catfish"
		Dogfish WaterAnimals = "dogfish"
	)
)
export enum WaterAnimals {
	Catfish = "catfish",
	Dogfish = "dogfish",
}

export enum LandAnimals {
	Cat = "cat",
	Dog = "dog",
}

export const Species = { ...github_com_foomo_gotsrpc_playground_server_services_wof.LandAnimals, ...github_com_foomo_gotsrpc_playground_server_services_wof.WaterAnimals }
export type Species = github_com_foomo_gotsrpc_playground_server_services_wof.LandAnimals | github_com_foomo_gotsrpc_playground_server_services_wof.WaterAnimals

Structs

type (
	Trip struct {
		Kind        string `json:"kind" gotsrpc:"type:'Trip'"`
		Destination string `json:"destination"`
	}
	Car struct {
		Kind        string `json:"kind" gotsrpc:"type:'Car'"`
		Model       string `json:"model"`
	}
	Pet struct {
		Kind        string `json:"kind" gotsrpc:"type:'Pet'"`
		Name        string `json:"name"`
	}
	Price struct {
		Trip *Trip `json:"trip,omitempty" gotsrpc:"union"`
		Car  *Car  `json:"car,omitempty" gotsrpc:"union"`
		Pet  *Pet  `json:"pet,omitempty" gotsrpc:"union"`
	}
)
export interface Trip {
	kind:'Trip';
	destination:string;
}

export interface Car {
	kind:'Car';
	model:string;
}

export interface Pet {
	kind:'Pet';
	name:string;
}

export type Price = github_com_foomo_gotsrpc_playground_server_services_wof.Trip | github_com_foomo_gotsrpc_playground_server_services_wof.Car | github_com_foomo_gotsrpc_playground_server_services_wof.Pet | undefined