Understanding Go through the Lens of TypeScript/JavaScript

aixart

Dhruv Kumar

Posted on October 25, 2024

Understanding Go through the Lens of TypeScript/JavaScript

If you're coming from a TypeScript/JavaScript background and diving into Go, it can be helpful to draw parallels between the two languages to speed up your learning. While they are fundamentally different in many ways (Go being a statically-typed, compiled language, and TypeScript/JavaScript being dynamically typed, interpreted or transpiled languages), there are some useful analogies that will help make Go more intuitive.

1. Structs in Go ≈ Types in TypeScript

In TypeScript, you define types and interfaces to describe the shape of objects. Similarly, Go has structs, which are used to define custom types. A struct can contain fields of different types, similar to how a TypeScript type or interface may contain different properties.

TypeScript:

type Book = {
  title: string;
  pages: number;
  read(): void;
}
Enter fullscreen mode Exit fullscreen mode

Go:

type Book struct {
    Title string
    Pages int
}

func (b Book) Read() {
    fmt.Println("Reading", b.Title)
}
Enter fullscreen mode Exit fullscreen mode

In both cases, you are defining the structure of an object. However, Go’s structs are more rigid and do not support inheritance, unlike TypeScript, which allows for more dynamic behavior with interfaces and class inheritance.

2. Methods in Go: Receivers ≈ Prototypes in JavaScript

In JavaScript, when you define a method on an object’s prototype, it’s associated with instances of that object. Go uses a similar concept with receiver functions that are tied to a specific struct. This feels similar to how functions are attached to objects in JavaScript via prototypes.

JavaScript:

function Book(title, pages) {
    this.title = title;
    this.pages = pages;
}

Book.prototype.read = function() {
    console.log("Reading", this.title);
}
Enter fullscreen mode Exit fullscreen mode

Go:

type Book struct {
    Title string
    Pages int
}

func (b Book) Read() {
    fmt.Println("Reading", b.Title)
}
Enter fullscreen mode Exit fullscreen mode

In Go, the Read method has a receiver (b Book), which acts similarly to how methods are associated with prototypes in JavaScript. It gives you the object’s instance (b here), letting you access the fields and use the method.

3. let, var, const in TypeScript ≈ Variable Declaration in Go

The way you declare variables in Go is reminiscent of JavaScript’s let, var, and const. In Go, variables are declared with var, and constants with const, much like TypeScript.

TypeScript:

let name: string = "TypeScript";
const maxItems: number = 100;
Enter fullscreen mode Exit fullscreen mode

Go:

var name string = "Go"
const maxItems int = 100
Enter fullscreen mode Exit fullscreen mode

The := shorthand in Go feels somewhat like JavaScript’s let in that it allows for quick variable declaration:

name := "Go" // type inference, like in TypeScript
Enter fullscreen mode Exit fullscreen mode

In Go, there is no distinction between let and const like in JavaScript. By default, all variables in Go are mutable when declared with var, meaning their values can be changed later. If you want to make a variable immutable in Go, you must explicitly use the const keyword. Unlike JavaScript, where you have both let for mutable variables and const for immutable ones, in Go, everything is mutable unless you declare it as const.

4. Go Interfaces ≈ TypeScript Interfaces (with differences)

TypeScript interfaces define the shape of objects, while Go interfaces define behavior (i.e., a set of methods an object must have). In Go, an object "implements" an interface implicitly by having all required methods, which contrasts with TypeScript's explicit implementation.

TypeScript:

interface Reader {
  read(): void;
}

class Book implements Reader {
  read() {
    console.log("Reading a book");
  }
}
Enter fullscreen mode Exit fullscreen mode

Go:

type Reader interface {
    Read()
}

type Book struct {
    Title string
}

func (b Book) Read() {
    fmt.Println("Reading", b.Title)
}
Enter fullscreen mode Exit fullscreen mode

In Go, any type that implements the Read method is considered to implement the Reader interface, even without explicitly declaring it.

5. Error Handling in Go ≈ Try-Catch in JavaScript (but different)

Error handling in Go feels very different compared to JavaScript’s try-catch. In Go, error handling is done explicitly with return values, while JavaScript uses exceptions.

JavaScript:

try {
    // Some code
} catch (error) {
    console.error(error);
}
Enter fullscreen mode Exit fullscreen mode

Go:

file, err := os.Open("file.txt")
if err != nil {
    log.Fatal(err)
}
Enter fullscreen mode Exit fullscreen mode

In Go, errors are returned from functions and need to be checked explicitly, which leads to more predictable control flow but requires more manual error handling compared to JavaScript’s try-catch mechanism.

6. Package System in Go ≈ ES Modules in TypeScript

In TypeScript, you organize your code into modules that can import/export other pieces of functionality. Go has a similar package system where each file is part of a package, and packages can import functionality from other packages.

TypeScript:

// module1.ts
export const greet = () => console.log("Hello");

// module2.ts
import { greet } from "./module1";
greet();
Enter fullscreen mode Exit fullscreen mode

Go:

// main.go
package main

import "fmt"

func main() {
    fmt.Println("Hello, Go")
}
Enter fullscreen mode Exit fullscreen mode

In Go, package main is the entry point of your application, similar to how a main file might serve as an entry point for a TypeScript project using ES modules.

7. Concurrency in Go: Goroutines ≈ Asynchronous Programming

JavaScript's asynchronous programming with async/await and promises feels somewhat analogous to Go’s goroutines. Goroutines allow functions to run concurrently, making Go’s concurrency model very powerful.

JavaScript:

async function fetchData() {
    const data = await fetch(url);
    console.log(data);
}
Enter fullscreen mode Exit fullscreen mode

Go:

func fetchData() {
    fmt.Println("Fetching data...")
}

go fetchData() // Runs concurrently
Enter fullscreen mode Exit fullscreen mode

With Go's goroutines, you can launch functions concurrently with the go keyword, while TypeScript achieves this through async/await and promises.

Conclusion

Switching from TypeScript/JavaScript to Go might seem daunting at first, but drawing these comparisons can help make the transition smoother. Understanding Go's stricter type system, explicit interfaces, and concurrency model will make your journey rewarding. Once you get the hang of Go’s more explicit and structured nature, you’ll appreciate its performance and reliability in building robust systems.

💖 💪 🙅 🚩
aixart
Dhruv Kumar

Posted on October 25, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related