Learning to program can feel overwhelming. There are countless tutorials, boot camps, and YouTube videos all pulling you in different directions, and most of them assume you already know something.
The result? Gaps in your understanding that haunt you for years. You memorize syntax without understanding what it means. You copy-paste code that works but can't explain why. When something breaks, you're stuck because you never built the mental model to reason about what's happening underneath.
The Programming Foundations Workshop is your ground-zero start to becoming a software developer. Built with TypeScript from the very first line, it takes you from zero prior programming experience through expressions, variables, types, functions, and beyond-- equipping you with the foundational knowledge that every concept in web development builds on.
No prior programming knowledge is required. If you can open an editor and run the workshop app, you're ready. And because this is how software is built today, you'll learn alongside AI-assisted tooling from the start-- building the skills to write, review, and understand code in a modern development workflow.
Expressions & Output
Every program needs a way to tell you what it's doing. Without output, you're flying blind-- writing code with no way to verify it works. This is the very first skill you need as a developer.
In this section, you'll get your programs talking back to you while learning the building blocks of every piece of code you'll ever write:
- Outputting values with
console.log - String expressions and concatenation
- Number expressions and arithmetic operators
- Escaping special characters in strings
- Template literals with interpolation and multiline support
Variables
Hardcoded values can only get you so far. Real programs need to store, reference, and update data as they run. Without a solid understanding of how variables work, you'll constantly be confused by unexpected behavior.
Variables are foundational to every program you'll ever write. Here you'll learn how to declare them, when to use each type, and a critical nuance that trips up even experienced developers:
- Declaring variables with
letandconst - Naming conventions and casing (camelCase, SCREAMING_SNAKE_CASE)
- Reassigning values with
letand compound operators like+= - The important distinction between reassignment and mutation
- Why
constdoesn't always mean the value can't change
Primitive Types
JavaScript has types whether you think about them or not. Every value in every variable carries a type, and ignoring that fact leads to bugs that are hard to track down. TypeScript makes these types explicit, catching entire categories of errors before your code ever runs.
This section introduces you to all seven primitive types and how TypeScript helps you work with them safely:
- Explicit type annotations with
number,string, andboolean - The difference between
nullandundefined - Special types:
bigintfor arbitrarily large numbers andsymbolfor unique identifiers - Type coercion and why it can surprise you
- Floating-point precision and practical considerations for working with numbers
Comparisons & Boolean Logic
Making decisions is at the heart of every program. Should this button be enabled? Does this user have access? Is the cart empty? All of these questions boil down to comparisons and boolean logic.
Getting comparisons wrong leads to subtle bugs that are painful to debug. This section gives you the tools to write conditions that behave exactly as you'd expect:
- Loose equality (
==) vs. strict equality (===) and why you should almost always use strict - Not-equal, greater-than, and less-than-or-equal-to operators
- Combining conditions with logical AND (
&&), OR (||), and NOT (!) - Order of operations with logical operators
- Using parentheses to make complex conditions explicit
Truthiness & Falsiness
JavaScript has a unique feature where every value has an inherent "truthiness" or "falsiness." This isn't a bug-- it's one of the most practical features of the language once you understand it. But misunderstanding it leads to some of the most confusing behavior new developers encounter.
Here you'll learn which values are truthy, which are falsy, and how to use this knowledge to write cleaner conditional logic:
- Coercing values to booleans with the
Booleanconstructor - The double-not (
!!) operator and when to use it - Falsy values:
0,"",null,undefined,false, andNaN - Practical patterns like checking array length and optional values
- Avoiding common pitfalls with logical operators and coercion
Functions
Up to this point, your programs run top to bottom and that's it. Functions change everything. They let you take a chunk of code, put it somewhere reusable, and call it from anywhere-- with different inputs each time.
Functions are the single most important building block for organizing and scaling your programs. This section takes you from writing your first function through passing functions as arguments to other functions:
- Function declarations with the
functionkeyword - Accepting parameters and specifying their types
- Return values and TypeScript's return type inference
- Arrow functions and implicit returns
- Passing functions as arguments to other functions
- Documenting your functions with JSDoc
Type Inference & Arrow Functions
TypeScript is smart. You don't have to type everything explicitly-- TypeScript can often figure out the types for you by looking at your code. Knowing when to lean on inference and when to be explicit is a skill that makes your code cleaner and your development faster.
This section also covers arrow functions, a concise alternative syntax you'll see everywhere in modern JavaScript and TypeScript:
- How TypeScript infers return types from your function body
- When explicit return types help catch bugs earlier
- Converting function declarations to arrow functions
- Implicit returns for single-expression functions
- The hoisting difference between declarations and expressions
- Function expressions as first-class values
Void & Never
Not every function returns something useful, and some code paths should never be reached. TypeScript has dedicated types for both of these situations, and understanding them helps you write more precise, self-documenting code.
This section introduces two TypeScript-specific concepts that complete your understanding of the type system's fundamentals:
- The
voidtype for functions that don't return a value - How
voidrelates toundefinedin practice - The
nevertype for functions that throw errors or never return - Using
neverto enforce exhaustive checks - Throwing errors to halt execution and signal failures
- Practical patterns for input validation with error throwing
