Babel Rosetta - HeyItWorked/babel-shelf GitHub Wiki
Side-by-side comparison of the same operations in every language. Use this as a quick-reference cheat sheet when switching between implementations.
// Go — models.go
type Book struct {
Id int `json:"id"`
Title string `json:"title"`
Author string `json:"author"`
Status string `json:"status"`
}// TypeScript — models.ts
export interface Book {
id: number;
title: string;
author: string;
status: BookStatus;
}# Python
@dataclass
class Book:
id: int
title: str
author: str
status: str// Gleam (coming soon)
pub type Book {
Book(id: Int, title: String, author: String, status: BookStatus)
}Pattern: Every language needs to define "what a book looks like." Go uses structs with tags, TS uses interfaces, Python uses dataclasses, Gleam uses custom types. The shape is identical — just the syntax differs.
// Go — string constants (no real enums)
const (
StatusWantToRead = "want to read"
StatusReading = "reading"
StatusFinished = "finished"
)// TypeScript — union type (compile-time only)
export type BookStatus = "want to read" | "reading" | "finished";
export const VALID_STATUSES: BookStatus[] = [STATUS_WANT_TO_READ, STATUS_READING, STATUS_FINISHED];# Python — Enum class
from enum import Enum
class BookStatus(str, Enum):
WANT_TO_READ = "want to read"
READING = "reading"
FINISHED = "finished"// Gleam — custom type (true algebraic type)
pub type BookStatus {
WantToRead
Reading
Finished
}| Language | Compiler catches invalid value? | Exhaustive match? |
|---|---|---|
| Go | No (just strings) | No |
| TypeScript | Yes (union type) | No (needs manual check) |
| Python | Partial (Enum) | No |
| Gleam | Yes (custom type) | Yes (compiler forces it) |
// Go
row := db.QueryRow(
`INSERT INTO books (title, author, status) VALUES ($1, $2, $3)
RETURNING id, title, author, status`,
book.Title, book.Author, book.Status,
)
err := row.Scan(&book.Id, &book.Title, &book.Author, &book.Status)// TypeScript
const result = await pool.query<Book>(
`INSERT INTO books (title, author, status) VALUES ($1, $2, $3)
RETURNING id, title, author, status`,
[book.title, book.author, book.status]
)
return result.rows[0]# Python (psycopg2)
cursor.execute(
"""INSERT INTO books (title, author, status) VALUES (%s, %s, %s)
RETURNING id, title, author, status""",
(book.title, book.author, book.status)
)
row = cursor.fetchone()Same SQL, different wrappers:
- Go: manual
Scaninto each field with&pointers - TS: auto-maps columns to object keys
- Python:
fetchone()returns a tuple (or dict withRealDictCursor)
// Go — explicit check, every time
book, err := insertBook(book)
if err != nil {
http.Error(w, "could not create book", 500)
return
}// TypeScript — try/catch (or just let it throw)
try {
const book = await insertBook(body)
return c.json(book, 201)
} catch (e) {
return c.text("could not create book", 500)
}
// Note: the actual codebase doesn't try/catch — it lets Hono catch uncaught errors# Python — try/except
try:
book = insert_book(body)
return jsonify(book), 201
except Exception:
return "could not create book", 500// Gleam — Result type + use keyword
use book <- result.try(insert_book(conn, title, author, status))
// if insert_book returns Error, the whole function short-circuits
json_response(encode_book(book), 201)// Go — stdlib path value
id, err := strconv.Atoi(r.PathValue("id"))
if err != nil {
http.Error(w, "invalid id", 400)
return
}// TypeScript — Hono param
const id = Number(c.req.param("id"))
if (isNaN(id)) {
return c.text("invalid id", 400)
}# Python Flask
@app.get("/books/<int:id>") # Flask parses for you
def get_book(id: int): ...// Gleam — pattern match + parse
case wisp.path_segments(req) {
["books", id_string] -> {
case int.parse(id_string) {
Ok(id) -> get_book(id, ctx)
Error(_) -> wisp.bad_request()
}
}
}// Go — manual encoding
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(book)// TypeScript — one-liner
return c.json(book, 201)# Python Flask
return jsonify(book), 201// Gleam — explicit encoding
wisp.json_response(
json.to_string_tree(encode_book(book)),
201
)Verbosity spectrum: TypeScript < Python < Gleam < Go
// Go — one line, blocks forever
http.ListenAndServe(":8080", router)// TypeScript (Bun) — export convention
export default { port: 8081, fetch: app.fetch }# Python Flask
app.run(port=8080)// Gleam — wisp + mist
wisp.mist_handler(handle_request, ctx)
|> mist.new
|> mist.port(8082)
|> mist.start_http// Go — httptest recorder
req, _ := http.NewRequest("POST", "/books", strings.NewReader(`{"title":"Dune"}`))
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
// check rr.Code, rr.Body// TypeScript — Hono's built-in test helper
const res = await app.request("/books", {
method: "POST",
body: JSON.stringify({ title: "Dune" }),
headers: { "Content-Type": "application/json" }
})
// check res.status, await res.json()# Python Flask
res = client.post("/books", json={"title": "Dune"})
# check res.status_code, res.get_json()Key insight: Go and TS both test without starting a real HTTP server. Go uses httptest.NewRecorder() to capture the response in memory. Hono's app.request() does the same thing. No network involved.