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

note

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

Go
type Greeting string
TypeScript
type Greeting = string;

Enumerations

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

Go
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
)
TypeScript
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

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

Other slice type examples

Structs

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

Nested slices

Go
[][]string
[][]int
// ...
TypeScript
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

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

Structs

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

Slices

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

Map types

Go and TypeScript support map / Record types:

tip

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

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

Nested map types

Go
type BrandID string
type BrandCarDirectory map[BrandID]map[ProductID]*Car
// or
type BrandCarDirectory map[BrandID]CarDirectory
TypeScript
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.

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

Idiomatic field names

Json tags allow controlling the name in TypeScript.

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

Optional and nullable fields

Go
type Basic struct {
Value string `json:"value"`
OptionalValue string `json:"optionalValue,omitempty"`
NullableValue *string `json:"nullableValue"`
}
TypeScript
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
Go
type Basic struct {
Value string `json:"value"`
Secret string `json:"-"`
}
TypeScript
type Basic interface {
value:string;
}

Union Types

When static types seem to be in the way

Scalars

Go
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"
)
)
TypeScript
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

Go
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"`
}
)
TypeScript
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