TS
GO

TypeScript to Go

10 lessons

Progress0%
1Introduction: Transpiled to Compiled Binary2Type Systems: Structural Interfaces3Functions4Objects to Structs5Generics6Error Handling7Async to Goroutines8Ecosystem9Testing10Go Standard Library
All Mirror Courses
TS
GO
Generics
MirrorLesson 5 of 10
Lesson 5

Generics

Generics

Introduction

In this lesson, you'll learn about generics in Go. Coming from TypeScript, you already have a foundation for understanding this concept. We'll build on that knowledge while highlighting the key differences.

Mirror Card
TS
From TypeScript:

In TypeScript, you're familiar with generics.

GO
In Go:

Go has its own approach to generics, which we'll explore step by step.

The Go Way

Let's see how Go handles this concept. Here's a typical example:

GO
Go Example
// Go 1.18+ generics
func Map[T, U any](slice []T, fn func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

func Filter[T any](slice []T, pred func(T) bool) []T {
    var result []T
    for _, v := range slice {
        if pred(v) { result = append(result, v) }
    }
    return result
}

// Constrained generics with type sets
type Number interface {
    ~int | ~float64
}

func Max[T Number](a, b T) T {
    if a >= b { return a }
    return b
}

Comparing to TypeScript

Here's how you might have written similar code in TypeScript:

TS
TypeScript (What you know)
function map<T, U>(arr: T[], fn: (item: T) => U): U[] {
  return arr.map(fn);
}

function filter<T>(arr: T[], pred: (item: T) => boolean): T[] {
  return arr.filter(pred);
}

// Constrained generics
function max<T extends { valueOf(): number }>(a: T, b: T): T {
  return a.valueOf() >= b.valueOf() ? a : b;
}
Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

Go 1.18+ added generics with [T any] syntax — similar to TypeScript's <T>

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

Go constraints use interface{} type sets with | — like TypeScript union constraints

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

The ~ prefix means 'any type whose underlying type is T' (e.g., ~int includes custom int types)

Mirror Card
TS
From TypeScript:

You may be used to different syntax or behavior.

GO
In Go:

Go generics are more limited than TypeScript — no conditional types or mapped types

Step-by-Step Breakdown

1. [T any] vs <T>

Go generics use [T any] where TypeScript uses <T>. any is the unconstrained type parameter — like TypeScript's unknown.

TS
TypeScript
function identity<T>(v: T): T { return v; }
GO
Go
func Identity[T any](v T) T { return v }

2. Type Sets for Constraints

Go constraints are interfaces that list acceptable types. The | operator creates a union. ~ means 'underlying type'. This replaces TypeScript's T extends union.

TS
TypeScript
function add<T extends number | string>(a: T, b: T): T {}
GO
Go
type Addable interface {
    ~int | ~float64 | ~string
}

func Add[T Addable](a, b T) T { return a + b }

3. golang.org/x/exp/slices

The standard library was slow to adopt generics. The golang.org/x/exp package provides generic slice utilities (slices.Map, slices.Filter) as the community standard.

TS
TypeScript
import { pipe } from "fp-ts/function"; // TS functional libs
GO
Go
// Go standard (1.21+):
import "slices"

sorted := slices.Sorted(slices.Values(mySlice))
idx, found := slices.BinarySearch(mySlice, target)

4. No Specialization

Go generics cannot be specialized for specific types. You cannot have different behavior for Map[string] vs Map[int]. TypeScript conditional types fill this gap but Go takes a simpler approach.

TS
TypeScript
type StringOrNumber<T> = T extends string ? string : number;
GO
Go
// Not possible in Go — generics are uniform
// Use type switches for runtime type-specific behavior:
func describe(v any) string {
    switch x := v.(type) {
    case int:    return fmt.Sprintf("int: %d", x)
    case string: return fmt.Sprintf("str: %s", x)
    default:     return "unknown"
    }
}

Common Mistakes

When coming from TypeScript, developers often make these mistakes:

  • Go 1.18+ added generics with [T any] syntax — similar to TypeScript's <T>
  • Go constraints use interface{} type sets with | — like TypeScript union constraints
  • The ~ prefix means 'any type whose underlying type is T' (e.g., ~int includes custom int types)
Common Pitfall
Don't assume Go works exactly like TypeScript. While the concepts may be similar, the syntax and behavior can differ significantly.

Key Takeaways

  • Go 1.18+ generics use [T any] syntax — similar to <T> in TypeScript
  • Constraints use type set interfaces with | for unions and ~ for underlying types
  • Go generics are intentionally simpler — no conditional or mapped types
  • Standard library generics (slices, maps packages) available from Go 1.21+
Rule of Thumb
The best way to learn is by doing. Try rewriting some of your TypeScript code in Go to practice these concepts.
PreviousNext