→
ZIGCurriculum
four modules. Start anywhere — the recommended path is in order, but every theme is browsable. Themes without exercises yet are visible so you can see what's coming.
Progress saves per exercise — re-open any one to continue where you left off. Nothing leaves your browser.
let count: number = 5;
const PI = 3.14;
function double(n: number): number {
return n * 2;
}var count: i32 = 5;
const PI: f64 = 3.14;
fn double(n: i32) i32 {
return n * 2;
} 1. Basics
8 themes · 72 exercises
The "you already know this, just spelled differently" module for Zig. Imports, entry points, variables, control flow, functions, the string-is-a-slice convention, and optionals. By the end, you trust that typeover's translation pattern works for Zig too, and writing a hello-world Zig program feels familiar.
1.1
Hello and output
Two reflexes Zig wants you to internalise on day one.
- Imports use a builtin, not a keyword. const std = @import("std");
binds the standard library to a name. There's no…
Zig defaults the other way from TypeScript. const is the default reflex; var is the explicit opt-in when you need to reassign. Type annotations come AFTER the name (`var x: i32…
Zig's if looks like TypeScript's: parens around the condition, optional braces around the body. The catch: Zig has no truthy values — the condition must be bool. switch is an…
1.4
while and for
Zig has while (cond) { ... } for condition-driven loops and for (slice) |item| { ... } for iteration. The C-style three-clause for (init; cond; step) is gone — its replacemen…
TypeScript has one numeric type — number — that swallows everything from booleans to billions. Zig is the opposite: every integer width is explicit (i8, i16, i32, i64, `u…
There's no String type in Zig. String literals are byte slices typed as []const u8 — same shape as any other slice of read-only bytes. Length comes from .len (a usize), ind…
1.8
Optionals (?T)
TypeScript uses T | null (or T | undefined) to mark "maybe absent" values; Zig's analogue is the type prefix ?T. A ?T value is either some T or null. Three idiomatic wa…
2. Types
4 themes · 36 exercises
Zig's type vocabulary is similar enough to TypeScript that you
can lean on the analogues — struct matches object literals,
enum matches string literal unions, union(enum) matches
discriminated unions. The diverging bits are pointers (*T,
*const T, [*]T, ?*T — each meaning something specific)
and arrays vs slices ([N]T length-in-type vs []T slice).
Lays the type foundation that Memory + Errors + Comptime build on.
TypeScript reaches for string-literal unions ("red" | "green" | "blue") for enums and discriminated unions ({ kind: "circle", radius: 5 } | { kind: "square", side: 3 }) for sum…
2.4
Arrays vs slices
Zig has two collection shapes where TypeScript has one. [N]T is a fixed-length array; the length N is part of the type, known at compile time. []T is a slice: a pointer plus a runt…
3. Memory
4 themes · 36 exercises
The friction module. Allocators are explicit: every dynamic
allocation goes through one, and you pick which. defer is
the structural tool that makes manual memory safe to write
(and read). Ownership is enforced by convention, not the
compiler — "whoever calls init calls deinit." Once
comfortable here, the rest of the Zig stdlib reads naturally.
Zig has no hidden allocations. Every dynamic alloc goes through an Allocator interface value, and you pick which. The three you meet first: page_allocator (OS page granularity, sim…
defer is Zig's structural cleanup tool: each defer statement runs when the enclosing block exits, in LIFO order. errdefer is the same idea, but it only fires when the function retu…
Zig has no borrow checker — ownership is convention, not enforcement. The rule that makes manual memory livable: whoever calls init is responsible for calling deinit. A function th…
4. Errors
4 themes · 36 exercises
Zig errors are first-class values from a finite set declared
per-API. error{ Empty, BadInput } declares a set; !T is the
error-union return type. try is sugar for "propagate-on-error,
unwrap-on-success." catch handles. There's no exception
hierarchy, no try/catch ladder, no fall-through — every error
case is named, every callsite is explicit. Builds on Module 3:
errdefer finally makes sense in its native habitat.
4.1
Error sets
An error set is a finite enumeration of named errors — declared as error{ Empty, BadDigit, ... }. Different APIs declare their own sets; the compiler tracks which errors a function…
4.2
try and catch
There are three ways to consume an error union. try expr is the propagator: on error, return the error to the caller; on success, unwrap the value. expr catch <default> substitutes…
A function that can fail declares a return type with a leading bang: !T means "either a T or an error." The error set is usually INFERRED from the function body — every return erro…
4.4
Panics vs errors
Errors are for conditions the caller should be expected to handle (bad input, out of memory, missing file). Panics are for conditions that indicate a programmer bug — invariants th…
typeover · curriculum · pass 2
← back to home