← Fundamentals
Guided lesson 7 questions · 6 languages

From source to a running program

Text in a file, a tool that checks it, and a run that goes line by line.

A program is text in a file. A tool checks the text and turns it into something the computer can run. Then the run starts at one fixed place and goes one line at a time.

Before you begin

Why this matters

Every program you write goes through the same steps: you edit the text, a tool checks it, and then it runs. When something goes wrong, the first question is which step it went wrong in. Knowing the steps tells you where to look.

What this helps you reason about

  • Predict the order of a program’s output from the order of its lines.
  • Tell a mistake found before the run, when nothing runs, from one found during the run, when the lines before it have already run.
  • Say on which line a run starts, and why a line written first may run later.

A TypeScript program is text in a file. A tool checks the text and turns it into a form the computer can run, and then the run goes one line at a time. This lesson follows that path, and shows which mistakes are found before the run and which appear during it.

Already know this? The short version
  • The TypeScript compiler, tsc, checks the source for syntax, names, and types, then writes plain JavaScript without the types. Node.js runs that JavaScript.
  • There is no main: Node.js runs the top-level code from the first line down. A function’s body runs only when it is called; return ends the call and hands a value back, while console.log only prints.
  • A compile error is reported before any line runs. tsc on its own still writes the JavaScript unless noEmitOnError is set; this stepper sets it, so the program never starts.
  • A run-time error, such as a RangeError, appears when its line runs: the output of earlier lines is already there, and later lines do not run. Dividing by zero is not one: 300 / 0 is Infinity.

Go to the final check· Go to the practice tickets

Words in this lesson (8)
source code
The text of a program, written in a programming language and saved in a file, such as main.ts.
function
A named group of lines that runs when the program calls it, by writing its name followed by parentheses, as in coolDown().
entry point
The place where a run starts. A TypeScript file has no main function: Node.js starts at the first line and runs the code outside every function, from top to bottom.
return value
The value a call gives back to the code that called it. return ends the call and supplies it; a function that ends without return gives undefined.
compiler
A program that checks your code and translates it into another form. The TypeScript compiler checks types, then removes them and produces plain JavaScript.
Node.js
A program that runs JavaScript outside a web browser. It runs the JavaScript that the TypeScript compiler writes.
compile error
A problem the TypeScript compiler finds before the program runs, such as a misspelled name or a value of the wrong type.
run-time error
A problem that appears only while the program runs, such as a RangeError. The lines before it have already run, and the program stops at that line unless the code handles the error.

Examples are focused snippets; imports, enclosing functions, or classes may be omitted. C examples use C11; Haskell examples use Haskell 2010. Expand the notes for language-specific depth.

01 / Program

What is a program?

A program is text. You write it in a file, such as main.ts, using the words and symbols of a programming language. This text is called source code.

Each line below is one instruction, and the semicolon marks where it ends. console.log(…) prints what is between the parentheses. Text in quotes is printed as it is. 2 * 400 is a calculation, so it prints 800. Text after // is a comment: the computer ignores it. Here the comments show the output.

main.ts
console.log("warm-up");
console.log("jog", 2 * 400, "metres");
console.log("sprint");
// warm-up
// jog 800 metres
// sprint

The lines run one at a time, from top to bottom, so the output comes in the order of the lines.

Experiment

Run a program one line at a time

Each stop is before its line runs. The highlighted line is the next one to run, not the one that just ran.

Why it matters To find which line printed something, step until the output appears, and look at the line the run has just left.

Predict the three output lines before running. Then move the sprint line so that it is the first line of the file, and predict the order again.

console.log("warm-up");
console.log("jog", 2 * 400, "metres");
console.log("sprint");
What to look for

Step and watch the highlighted line and the output panel. The frame list, the stepper’s list of functions that are running, shows <top level>: the stepper’s name for code outside every function. Each line’s output appears when the stepper moves past that line. Here Step stops twice on every line. A stepper can stop more than once on a line; that is normal for the debugger, the tool that pauses the program at each stop. The last stop is on line 3, before sprint is printed; sprint appears when the run ends. After the edit, the output is sprint, warm-up, jog 800 metres.

Expected output

warm-up
jog 800 metres
sprint

02 / Start

Where does the run start?

A function is a named group of lines. function coolDown(): void { … } defines a function named coolDown. The lines between the braces are its body, and void says that it gives nothing back. Defining a function does not run its body.

The body runs when the program calls the function, by writing its name followed by parentheses: coolDown(). Then the run goes into the body, runs its lines in order, and comes back to the line after the call.

The place where a run starts is called the entry point. TypeScript has no special starting function. Node.js starts at the first line of the file and runs the code outside every function, from top to bottom. So the first line that runs here is console.log("race").

main.ts
function coolDown(): void {
  console.log("walk");
  console.log("stretch");
}

console.log("race");
coolDown();
console.log("done");
// race, walk, stretch, done

The run starts at the entry point; a function’s body runs only when the function is called.

Coming from Java: There is no main method to look for: every line outside a function runs, in order, as soon as the file is run.

Experiment

Find where the run starts

The first stop is at the entry point: the definition of the function makes no stop at all. The stops inside the function come from the call, and after its last line the run goes back to the line after the call.

Why it matters Read a program from its entry point, and follow each call into the function it names.

coolDown is written first, at the top of the file. Predict the line the run starts on, and the order of the four output lines. Then delete the line coolDown(); and predict again.

function coolDown(): void {
  console.log("walk");
  console.log("stretch");
}

console.log("race");
coolDown();
console.log("done");
What to look for

The first stop is on line 6, console.log("race"): the run skipped the body of coolDown. The variables panel lists coolDown as function coolDown(), the function itself. At line 7, the next stop is inside coolDown, on line 2, and the frame list shows coolDown above <top level>. After line 4, the run comes back to line 8. The run prints race, walk, stretch, done. After the edit, the stepper never stops inside coolDown, and the run prints only race and done.

Expected output

race
walk
stretch
done

03 / Return

What does return do?

A function can also give a value back. return ends the function and hands a value to the line that called it. The call then stands for that value, as if you had written the value there.

lapTime below has two parameters, seconds and laps: names for the values written in the call. lapTime(300, 4) runs the body with seconds 300 and laps 4, and return hands back 75. const time = … gives the name time to that value. Function calls follows a call step by step.

Printing is different. console.log shows text to a person reading the screen; it does not hand anything back to the program. If lapTime printed 75 instead of returning it, the line that called it would get undefined, a value that means “no value”.

main.ts
function lapTime(seconds: number, laps: number): number {
  return seconds / laps;
}

const time = lapTime(300, 4);
console.log("per lap:", time); // per lap: 75

return hands a value back and ends the function; printing only shows text on the screen.

04 / Build

What turns the text into a running program?

The computer cannot run TypeScript text directly. A compiler is a program that checks your code and translates it into another form. The TypeScript compiler, called tsc, checks main.ts, removes the types, and writes the same program as plain JavaScript in a file named main.js.

Node.js is a program that runs JavaScript. It reads main.js and runs it, from the first line.

So the cycle is: edit main.ts, compile it to main.js, and run main.js. In a terminal, a window where you type commands, the two steps are tsc main.ts and node main.js. Each command is the name of a program, then the file it works on. The stepper on this page does both steps for you each time you run an experiment.

A picture of the edit, build, and run cycle. The boxes are files and output, not memory.

A conceptual model, not a physical memory layout or live code execution.

1 / 3

Edit

main.ts
TypeScript source code

You write source code in main.ts.

Edit the source, let the compiler check it and write JavaScript, then run that JavaScript.

Precisely: the stepper’s tools

The stepper compiles with the TypeScript compiler in strict mode, which turns on its stricter checks, and runs the JavaScript in Node.js 22 under a debugger. Some tools run TypeScript by removing the types without checking them. With those tools, a type error is not reported before the run.

05 / Before running

What is checked before the program runs?

Before anything runs, the compiler reads the whole file and checks it. It checks the grammar of the language, called syntax: for example, that every opening parenthesis has a closing one. It checks that every name you use exists. And it checks types. A type is the kind of a value, such as a number or text, and it decides which operations make sense for the value.

A problem found by these checks is called a compile error. The compiler reports it with its line number, and the program does not run at all: not even the lines above the mistake. Here the second line misspells console, and the compiler reports Line 2: Cannot find name 'consle'. Did you mean 'console'?

main.ts
console.log("start");
consle.log(4 * 400);
console.log("finish");
// Nothing is printed: the program does not run.

A compile error stops the program before its first line runs.

Coming from Python: Python finds a misspelled name only when its line runs, after the lines above it have printed. The TypeScript compiler reports it before any line runs.

Precisely: tsc still writes JavaScript

By default, tsc reports a type error and still writes the JavaScript file, and Node.js would run it. The compiler setting noEmitOnError makes tsc write nothing when there is an error. The stepper uses that setting, so a program with a compile error never starts. Many projects turn it on too.

Experiment

Make a mistake the compiler finds

The edit is a type error, not a misspelling: every name is right, but the types do not fit. The compiler finds type errors in the same check as misspelled names, before any line runs.

Why it matters If a program prints nothing at all, first check whether it compiled.

Predict the three output lines. Then change 4 * 400 to 4 * "400", with quotes around 400, and predict: is start still printed?

console.log("start");
console.log(4 * 400);
console.log("finish");
What to look for

Before the edit, the run stops on each line and prints start, 1600, finish. After the edit, there are no stops and no output, not even start. The stepper shows the compiler’s message instead: Line 2: The right-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type. "400" in quotes is text, and * needs a number on each side.

Expected output

start
1600
finish

06 / While running

What can go wrong while the program runs?

Some problems cannot be found by reading the text. They depend on the values the program has while it runs. A problem that appears only while the program runs is called a run-time error.

const laps = 3 gives the name laps to the number 3. "=".repeat(laps) makes a text of laps copies of "=", so this program prints ===. The compiler is satisfied: laps is a number, and repeat needs a number. If laps were -1, the types would still be right, but no text has -1 copies. The run would stop at that line with RangeError: Invalid count value: -1.

When a run-time error stops the program, the lines before it have already run, and their output is already on the screen. The lines after it never run.

main.ts
const laps = 3;
console.log("start");
console.log("=".repeat(laps));
console.log("finish");
// start
// ===
// finish

A run-time error stops the program at its line; the lines before it have already run.

Coming from Java: Dividing by zero is not an error in JavaScript: 300 / 0 gives Infinity, where Java throws an ArithmeticException for whole numbers.

Precisely: exceptions

JavaScript reports a run-time error by throwing an exception, here a RangeError. Code can catch an exception with try and catch and continue. An exception that nothing catches stops the program, and Node.js prints it to standard error, a second output stream. The stepper shows it below the output instead.

Experiment

Make a mistake that appears only while running

The compiler checks types, not values. -1 is a number, the type repeat needs, so only the run can find the problem.

Why it matters The output before a run-time error shows how far the program got.

Predict the output. Then change const laps = 3; to const laps = -1; and predict which lines are still printed.

const laps = 3;
console.log("start");
console.log("=".repeat(laps));
console.log("finish");
What to look for

Before the edit, laps shows 3 in the variables panel, and the run prints start, ===, finish. After the edit, the program compiles and starts: laps shows -1, and start is printed. At line 3 the run stops with RangeError: Invalid count value: -1, at <top level> (line 3). finish is never printed.

Expected output

start
===
finish

07 / Try it

Can you explain a fresh example?

Predict the output, line by line, before you reveal the answer. Then predict what changes if the last line is misspelled as consle.log("match ends").

main.ts
function score(): number {
  console.log("counting");
  return 3;
}

console.log("match starts");
const goals = score();
console.log("goals:", goals);
console.log("match ends");

What does the program print, in order? What does it print with the misspelled last line?

Reveal the reasoning

match starts, counting, goals: 3, match ends. The run starts at the first line outside a function, so match starts comes first. The call score() runs the body of score, which prints counting and returns 3, and goals gets 3. With the misspelled last line, the program prints nothing at all: the misspelling is a compile error, so not even the first line runs.

The next lesson, What is a value?, looks at the numbers and text that these lines work with.

Practice tickets

  1. BUILD-101 · Trampoline final scores are too high whenever there is a bonus → Free
  2. BUILD-102 · Runners past the marathon finish see negative kilometres → Sign in · Pro
  3. BUILD-103 · Archery totals look right on screen but are saved as 0 → Sign in · Pro

Keep exploring

What is a value? →

Primary references