https://github.com/widmogrod/mkunion
Strongly typed union type in golang.
https://github.com/widmogrod/mkunion
generator go golang golang-library golang-tools reducer traversal union-types visitor-pattern
Last synced: 6 months ago
JSON representation
Strongly typed union type in golang.
- Host: GitHub
- URL: https://github.com/widmogrod/mkunion
- Owner: widmogrod
- License: mit
- Created: 2022-09-26T10:13:54.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-07-14T20:55:32.000Z (almost 2 years ago)
- Last Synced: 2024-07-15T13:10:26.415Z (almost 2 years ago)
- Topics: generator, go, golang, golang-library, golang-tools, reducer, traversal, union-types, visitor-pattern
- Language: Go
- Homepage: https://widmogrod.github.io/mkunion/
- Size: 4.9 MB
- Stars: 5
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Roadmap: docs/roadmap.md
Awesome Lists containing this project
README
# Welcome to MkUnion
[](https://pkg.go.dev/github.com/widmogrod/mkunion)
[](https://goreportcard.com/report/github.com/widmogrod/mkunion)
[](https://codecov.io/gh/widmogrod/mkunion)
```bash
go install github.com/widmogrod/mkunion/cmd/mkunion@v1.26.1
```
```
mkunion watch -g ./...
```
## About
Strongly typed **union type** in golang that supports generics*.
* with exhaustive _pattern matching_ support
* with _json marshalling_ including generics
* and as a bonus, can generate compatible TypeScript types for end-to-end type safety in your application
## Why
Historically, in languages like Go that lack native union types, developers have resorted to workarounds such as the Visitor pattern or `iota` with `switch` statements.
The Visitor pattern requires a lot of boilerplate code and manual crafting of the `Accept` method for each type in the union.
Using `iota` and `switch` statements is not type-safe and can lead to runtime errors, especially when a new type is added and not all `case` statements are updated.
On top of that, any data marshalling, like to/from JSON, requires additional, handcrafted code to make it work.
MkUnion solves all of these problems by generating opinionated and strongly typed, meaningful code for you.
## Examples
### Example 1: Union definition and pattern matching with JSON marshaling
```go
//go:tag mkunion:"Shape"
type (
Circle struct{ Radius float64 }
Rectangle struct{ Width, Height float64 }
Triangle struct{ Base, Height float64 }
)
// Generated code provides:
area := MatchShapeR1(
shape,
func(c *Circle) float64 { return math.Pi * c.Radius * c.Radius },
func(r *Rectangle) float64 { return r.Width * r.Height },
func(t *Triangle) float64 { return 0.5 * t.Base * t.Height },
)
```
### Example 2: Result Type for Error Handling
```go
//go:tag mkunion:"Option[T]"
type (
None[T any] struct{}
Some[T any] struct{ Value T }
)
//go:tag mkunion:"Result[T, E]"
type (
Ok[T, E any] struct{ Value T }
Err[T, E any] struct{ Error E }
)
type User struct{ Name string }
type APIError struct {
Code int
Message string
}
// FetchResult combine unions for rich error handling
type FetchResult = Result[Option[User], APIError]
// handleFetch uses nested pattern matching to handle result
func handleFetch(result FetchResult) string {
return MatchResultR1(result,
func(ok *Ok[Option[User], APIError]) string {
return MatchOptionR1(ok.Value,
func(*None[User]) string { return "User not found" },
func(some *Some[User]) string {
return fmt.Sprintf("Found user: %s", some.Value.Name)
},
)
},
func(err *Err[Option[User], APIError]) string {
return fmt.Sprintf("API error: %v", err.Error)
},
)
}
```
**Important:** Generic unions MUST specify their type parameters in the tag. The type parameter names in the tag must match those used in the variant types.
### Example 3: AST and Recursive Types
```go title="example/calculator_example.go"
//go:tag mkunion:"Calc"
type (
Lit struct{ V int }
Sum struct{ Left, Right Calc }
Mul struct{ Left, Right Calc }
)
```
### Example 4: States for State Machines or Events for Event Sourcing
```go
//go:tag mkunion:"OrderState"
type (
Draft struct{ Items []Item }
Submitted struct{ OrderID string; Items []Item }
Shipped struct{ OrderID string; TrackingNumber string }
Delivered struct{ OrderID string; DeliveredAt time.Time }
)
```
### Example 5: HTTP API responses
```go
//go:tag mkunion:"APIResponse[T]"
type (
Success[T any] struct{ Data T; Status int }
ValidationError[T any] struct{ Errors []string }
ServerError[T any] struct{ Message string; Code string }
)
```
### Example 6: Configuration type
```go
//go:tag mkunion:"Config"
type (
FileConfig struct{ Path string }
EnvConfig struct{ Prefix string }
DefaultConfig struct{}
)
```
## Next
- Read [getting started](https://widmogrod.github.io/mkunion/getting_started/) to learn more.
- Learn more about [value proposition](https://widmogrod.github.io/mkunion/value_proposition/).