M Logo
๐Ÿ“ TypeScript from Zero ยท Part 25 of 50

TypeScript Async Await for Beginners: setTimeout, Promises and the Forgotten await

November 6, 2026

Welcome to episode 25 of TypeScript from Zero, a series for complete beginners (no JavaScript needed). Welcome back to TypeScript from zero! Today: code that has to wait. Reading a file, asking a server, waiting a second: none of this is instant, and a program must not freeze while it waits. We are in the shop project, with a new file called async.ts. Every code block below is the exact code and output from the video, ready to copy.

Setup

We start in the terminal and open the project in VS Code:

bash
cd shop
touch src/async.ts
code .

1. Callback

The simplest tool is set timeout. We give it a function, and a time in milliseconds. The function is called later. Look at the order: first, then second, and only after one second, the message from the timer. The program did not wait. It moved on. That function is called a callback.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
text
$ node src/async.ts
first
second
one second later

2. Promise

Callbacks get messy, so there is a nicer tool. A promise is an object that stands for a value that will arrive later. Our wait function returns a promise of nothing, which is void, and it is finished when the timer ends. With dot then, we say what to do next.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
function wait(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
wait(500).then(() => console.log("done waiting"));
text
$ node src/async.ts
first
second
done waiting
one second later

3. async await

Even nicer: the words async and await. Await pauses the function until the promise is ready, and gives us its value. Inside an async function, the code reads from top to bottom, like normal code. And the return type is a promise of a number, not a number, because the answer comes later.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
function wait(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
wait(500).then(() => console.log("done waiting"));
async function getNumber(): Promise<number> {
  await wait(500);
  return 42;
}
async function main() {
  const n = await getNumber();
  console.log("Got", n + 1);
}
main();
text
$ node src/async.ts
first
second
done waiting
Got 43
one second later

4. Forgotten await

The most common mistake: we forget the await. Now bad is not a number, but a promise. Node happily adds one to it and prints a strange text: object Promise one. tsc catches it: operator plus can not be applied to types promise of number, and one. It even asks: did you forget to use await? TS2365.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
function wait(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
wait(500).then(() => console.log("done waiting"));
async function getNumber(): Promise<number> {
  await wait(500);
  return 42;
}
async function main() {
  const n = await getNumber();
  console.log("Got", n + 1);
}
main();
const bad = getNumber();
console.log(bad + 1);
text
$ node src/async.ts
first
second
[object Promise]1
done waiting
Got 43
one second later
text
$ npx tsc --noEmit
src/async.ts:20:13 - error TS2365: Operator '+' cannot be applied to types 'Promise<number>' and '1'.

20 console.log(bad + 1);
               ~~~~~~~

  src/async.ts:20:13 - Did you forget to use 'await'?
    20 console.log(bad + 1);
                   ~~~~~~~

Found 1 error in src/async.ts:20

5. Fix

We delete those two lines, and tsc is quiet again.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
function wait(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
wait(500).then(() => console.log("done waiting"));
async function getNumber(): Promise<number> {
  await wait(500);
  return 42;
}
async function main() {
  const n = await getNumber();
  console.log("Got", n + 1);
}
main();
bash
$ npx tsc --noEmit

6. Top level

Because our project is a module, we can also use await at the top level of the file, with no main function. We wait, and then print the number.

src/async.ts:

ts
console.log("first");
setTimeout(() => {
  console.log("one second later");
}, 1000);
console.log("second");
function wait(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms));
}
wait(500).then(() => console.log("done waiting"));
async function getNumber(): Promise<number> {
  await wait(500);
  return 42;
}
async function main() {
  const n = await getNumber();
  console.log("Got", n + 1);
}
main();
const top = await getNumber();
console.log("Top level:", top);
text
$ node src/async.ts
first
second
done waiting
Got 43
Top level: 42
one second later

Recap

Today: set timeout and callbacks, promises with then, async and await, the type promise of T, and the forgotten await. This was the last episode of the type system part. Next episode: we start a real project, a task tracker for the command line.

ยฉ 2026 All Rights Reserved By Mahmudul Alam