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