Skip to content

Pointers

TypeScript does not have explicit pointers

Section titled “TypeScript does not have explicit pointers”

In TypeScript (and JavaScript), objects are always passed by reference automatically. You never write “give me the address of this variable.” The runtime handles memory invisibly.

Go exposes memory addresses explicitly. You choose whether a function receives a copy of a value or a pointer to the original. That choice has real consequences for correctness and performance.

&x gives you a pointer to x — the memory address where x lives. *p dereferences pointer p — it reads or writes the value at that address.

TypeScript
// TypeScript — objects are implicitly shared
function increment(obj: { count: number }) {
obj.count++; // mutates the original (reference)
}
const counter = { count: 0 };
increment(counter);
console.log(counter.count); // 1
// BUT primitives are always copied:
function addOne(n: number): number {
return n + 1; // n is a copy — caller unchanged
}
let x = 5;
addOne(x);
console.log(x); // still 5
Go
// Go — primitives copied by default; use * to opt in to mutation
func increment(n *int) {
*n++ // dereference and mutate
}
func main() {
x := 42
increment(&x) // pass address of x
fmt.Println(x) // 43 — x was mutated
// Without pointer — value is copied, caller unchanged
// increment(x) would be a compile error (type mismatch)
}

Every type T has a corresponding pointer type *T. A pointer variable holds an address, not a value.

TypeScript
// TypeScript has no pointer types
// The closest is a wrapper object or ref pattern:
const ref = { current: 0 }; // manual "pointer" idiom
Go
var p *int // p is a pointer to int, value is nil
x := 10
p = &x // p now holds the address of x
fmt.Println(*p) // 10 — dereference to read
*p = 20 // write through pointer
fmt.Println(x) // 20

There are two main reasons to use a pointer:

  1. Mutation — you want a function to modify the caller’s variable (not work on a copy).
  2. Efficiency — the struct is large and copying it on every call would be wasteful.

For small structs (2–3 fields) passed read-only, value semantics are usually fine. For large structs or anywhere you need mutation, use a pointer.

TypeScript
// TypeScript — structs/objects always pass by reference
// You have no choice; the runtime decides
interface Config { host: string; port: number; }
function connect(cfg: Config) { /* cfg is a reference */ }
Go
type Config struct {
Host string
Port int
}
// Value receiver — method gets a copy; cannot modify original
func (c Config) String() string {
return fmt.Sprintf("%s:%d", c.Host, c.Port)
}
// Pointer receiver — method can modify the original
func (c *Config) SetPort(p int) {
c.Port = p
}
func main() {
cfg := Config{Host: "localhost", Port: 8080}
cfg.SetPort(9090)
fmt.Println(cfg.String()) // localhost:9090
}
package main
import "fmt"
func increment(n *int) {
*n++
}
func swap(a, b *int) {
*a, *b = *b, *a
}
func main() {
x := 42
fmt.Println("before:", x)
increment(&x)
fmt.Println("after increment:", x)
a, b := 10, 20
fmt.Printf("before swap: a=%d b=%d\n", a, b)
swap(&a, &b)
fmt.Printf("after swap: a=%d b=%d\n", a, b)
// Pointer to struct
type Point struct{ X, Y int }
p := &Point{X: 1, Y: 2}
p.X = 99 // Go auto-dereferences: (*p).X = 99
fmt.Println("point:", *p)
}
What does &x mean in Go?
What does *p mean when p is a pointer?
What is the zero value of a pointer variable in Go?
You have func double(n int). Which call would let double modify the caller's variable?