JavaScript + TypeScript
A growing reference to the values, types, and language features that make up JavaScript and TypeScript.
77 of 77 entries published. Published entries are linked; the rest are planned.
Prerequisites
Start here: install the tools, create the project, and wire the editor to Deno.
Install Deno and check that it works
One command installs the runtime that reads, checks, and runs every file here, and then you ask the tool itself to confirm it.
Install Zed
Deno runs programs; you still need somewhere to write them, and this editor is unusually good at showing what TypeScript is thinking.
Create the course project
One workspace, set up properly once, so a program you wrote weeks ago is still where you left it.
Configure this Zed project to use Deno
An editor understands your code by consulting a language server, and this project needs Deno's rather than the general-purpose one.
Run and watch the current file from the editor
Optional: a task and a keystroke that run the file you are editing, with the typed command still the ground truth.
Values
What a value is, when two of them are the same, and what absence looks like. The most heavily linked-to entries in the series are here.
Values and references
Primitives are copied and objects are shared, and that one line explains a dozen surprises.
Equality
JavaScript compares values four different ways, and only one of them is the one to write.
Nothing, twice
JavaScript has two values for absence, and knowing which one produces each is most of the fight.
Truthiness
Eight values are falsy and everything else is truthy, and the whole skill is knowing which eight.
Numbers
There is one number type, it is a binary float, and everything surprising follows from that.
Conversion and coercion
A value changes type because you asked, or because an operation asked for you.
Ordering and sorting
Which value comes first is a different question from whether two are the same.
What a type is
Types as sets of values, which is the model every TypeScript entry after this point assumes.
What a type is
Types are sets of values, and the checker proves set membership without running your program.
Unions and narrowing
A union is two sets joined, and narrowing is the checker reading the checks you already write.
any, unknown, and never
The widest and narrowest types, and why one of the wide ones is a hole.
Names
Where a name can be seen, when it may be used, and what a function carries with it.
Scope and declarations
A declaration says where a name can be seen and when it may be used.
Assignment
Putting a value into a storage location, and the three operators that sometimes decline to.
Closures
A function carries a live connection to where it was written, and every function has one.
Symbols
A primitive whose only feature is being unlike every other value, and what that buys.
Absence, on purpose
Where to put the value that means end of input, no match, or not found.
Sentinels and discriminated unions
A special value can sit beside the ordinary ones or wrap around them, and the choice is forced more often than it looks.
Text
Strings, the three things called a character, and the small language for searching them.
Text, and the three things called a character
A string counts code units, a reader counts something else, and the gap explains a lot of bugs.
Strings
Immutable text, a large method surface, and four ways to make one that all fail differently.
Tagged templates
Put a function before a template literal and it receives the text and the values separately.
Regular expressions
A small language for matching text, with two parts, one flag you should always use, and a readability problem you can solve.
Unicode in patterns
One flag decides whether a pattern matches code units or code points, and the newer one adds properties, sequences, and set operations.
Matching and replacing
Six methods for running a pattern against a string, and the mutable property that makes the older ones dangerous.
Control flow
Asking one question, and repeating work.
Iteration
The protocol underneath for-of, and the lazy methods that now sit on top of it.
Iterables and iterators
One protocol sits under for-of, spread, destructuring and the rest, and knowing it tells you which sources you can loop over twice.
Iterator helpers
Iterators have methods now, they are lazy, and the pipeline you build with them is consumed exactly once.
Functions
One entity doing three jobs, the parameter the call fills in, and who counts the arguments.
Functions
One entity does three jobs and four entities each do one, and every specialization is a role it refuses to play.
The value of this
this is an implicit parameter the call fills in, not something the function owns, and every surprise about it follows from that one sentence.
Parameters and arguments
JavaScript never counts the arguments and TypeScript always does, which changes what every feature in this area is actually for.
Objects
Lookup tables, objects written down directly, and the chain that a missing property walks up.
Objects as dictionaries
An object will serve as a lookup table, a Map usually serves better, and the reasons are specific enough to decide by.
Objects
A set of key-value slots you can write down directly, and the two operations worth understanding properly are copying and reaching in.
Prototypes and inheritance
Every object has a prototype, reading a missing property continues up the chain, and instanceof is nothing more than a question about that chain.
Classes
A factory for objects, the two unrelated features called private, and what extends connects.
Classes
A factory for objects and a compact way to set up a prototype chain, with a gap between how it looks and how it works that is worth seeing once.
Private class members
TypeScript has two unrelated features called private, one enforced by the checker and one by the runtime, and the difference shows up in your JSON.
Subclassing
extends connects two classes twice, and the surprises all come from there, including one initialization order that quietly discards your work.
Errors
Moving a decision up to the level that can make it, and choosing what to throw.
Errors and exceptions
A throw moves the decision to the level that can make it, and TypeScript's one contribution is making you admit you do not know what you caught.
Designing error types
Four choices for what to throw, and the one thing worth knowing about each is what survives the trip to whoever reads it.
Modules
A file as a private scope with a declared boundary, and how a specifier becomes a URL.
Modules
A file is a private scope with a declared boundary, and the imports on the other side of that boundary are live views rather than copies.
Module specifiers
Every specifier resolves to a URL, and the only hard part is the kind that needs something else to say which URL.
Arrays
The operations that change one, the callbacks that copy instead, and the pattern that takes one apart.
Arrays
An object whose keys happen to be numbers, with a length that maintains itself, which explains the convenient parts and every strange one.
Mutating arrays
Eleven operations change an array and everything else copies it, and since ES2023 each of the eleven has a twin that does not.
Transforming arrays
Four callbacks cover almost everything, they all take the same three arguments, and none of them changes the array you called them on.
Destructuring
A pattern written where a name would go, shaped like the data it takes apart.
Keyed collections
Any value to any value, each value once, and the versions that let their keys be collected.
Maps
Any value to any value, in insertion order, with keys compared by identity for objects and by value for primitives.
Sets
Each value once, membership in constant time, and since ES2025 real set algebra with a protocol for what counts as another set.
Weak collections
A WeakMap and a WeakSet let their keys be collected, and every restriction they have is what makes that possible.
Async
A function that can pause, a container for a result that does not exist yet, and the one thread under both.
Generators
A function that can pause, which turns out to be the shortest way to produce values on demand.
Promises
A container for a result that does not exist yet, settling once, and in Deno a rejection nobody handles ends the process.
Async functions
An async function returns a promise and await unwraps one, which is enough to make ordinary control flow work on asynchronous code.
Promise combinators
Four functions take many promises and give back one, and choosing between them is choosing what done means.
Async iteration
The iteration protocol with one change, a promise around the whole result, and async generators as the only way to transform one.
The event loop
One thread, one task at a time, each task finishing before the next begins, and every asynchronous feature in the language is a consequence.
Data at the boundary
What a program meets on the way in and out: parsed text, time, and raw bytes.
JSON
Six kinds of value, a list of things that vanish without complaint, and the main door through which any enters a typed program.
Dates and times
Temporal is in Deno now, so the advice is no longer avoid Date and wait, it is use Temporal and convert at the boundary.
Buffers and views
An ArrayBuffer is bytes with no meaning, a view supplies one, and the choice between two kinds of view is a choice about who owns the format.
Typed arrays
A fixed-length window onto raw bytes, and in Deno the everyday currency of files, hashes, and text.
Describing shapes
Structural typing proper, over objects, the two spellings for one idea, functions, and classes.
Object types
A shape description matches by structure, not by declaration, and the one place where TypeScript breaks its own rule to catch your typos.
Interfaces and type aliases
Two spellings for one idea, one open and one closed, and two ways of combining types that are not the same operation.
Function types
A function's type is its parameters and its return type, three ways to write one, and the assignability rules that decide which functions fit.
Overloading
Four ways to give one function several signatures, the error message that explains the rule, and the reason two function names usually win.
Typing classes
Everything TypeScript adds to a class body is a visibility rule, a promise about initialization, or a contract with an interface, and none of it exists at run time.
The type toolkit
Write checks, types that refuse to be interchangeable, classes as values, and what replaces an enum.
Read-only
readonly is a write check on one member, it does not travel across a boundary, and the read-only collection types work by a completely different mechanism.
Typing arrays
Two kinds of array type, two notations for one of them, and an inference that always guesses the same one.
Nominal types and branding
TypeScript compares structure, so two unrelated types with the same members are one type. Branding is how you opt out, and it costs nothing at run time.
Classes as values
A class is a value, and the type of that value is not the type of its instances. Everything here follows from keeping the two apart.
Enums
The one TypeScript construct that emits JavaScript, what it compiles to, and the three reasons the recommendation is to reach for something else.
Enum patterns
Four JavaScript patterns that replace the enum, and the three jobs that decide which one you want.
Computing with types
The type-level if, loop, and string, and how to test that any of it does what you think.
Testing types
A type-level test is a compile error you arranged on purpose, which means it only exists while something is type-checking, and the one command that makes it disappear without a word.
keyof and indexed access
The two operators that read a type, the number keys that are not string keys, and how to make the compiler print a type it would rather keep folded.
Conditional types
The type-level if, the distribution nobody expects, the two ways never ruins a predicate, and infer as destructuring for types.
Mapped types
The type-level loop, the four modifiers, how Record and Partial and Pick are written, and the two properties nobody can detect without a trick.
Template literal types
Building string types by interpolation, taking them apart with infer, the two ceilings you will hit, and the split that disagrees with String.prototype.split.
Tuple types
One type per position, the three-part syntax and the rule that is a parse error, what spreading normalises to, labels that do nothing, and recursion as the only loop.