Skip to lesson

learningtypescript.org / basics / 01-introduction · lesson 1 of 25

TL;DR

Start learning TypeScript from scratch. Understand why TypeScript improves JavaScript with static types for scalable applications.

Key concepts

  • learn TypeScript
  • TypeScript tutorial
  • TypeScript basics
  • TypeScript for beginners

Introduction to TypeScript

TL;DR — TypeScript is JavaScript with static types. You add type annotations (: string, : number) to catch errors at compile time, get full IDE autocomplete, and ship more reliable code. TypeScript compiles to plain JavaScript — the type annotations are erased, so they add no runtime cost. (A few features — enum, decorators, namespaces, and constructor parameter properties — do emit real JavaScript; you'll meet all but namespaces later in this course.)

Welcome to your first lesson in TypeScript programming! In this introduction, we'll cover what TypeScript is, why it's become incredibly popular, and what makes it an excellent choice for modern software development.

What You'll Learn

By the end of this lesson you will write a small program that describes a course — building a string, a sentence and a boolean from typed values — and prove it correct with checks that fail until each value is right. Along the way you will meet the one thing that makes TypeScript different from JavaScript: a second tool, the compiler, that reads your code before it ever runs and refuses some of it.

This lesson is the front door to the whole course. Everything later — modelling data, narrowing unions, writing generic functions — rests on the two ideas here: an annotation is a promise you write down, and the compiler is what checks it. What is assumed is JavaScript itself. You cannot learn TypeScript without knowing JavaScript, because TypeScript is a type layer added on top of it: the values, the functions and the control flow are all JavaScript's, and what you are adding is a description of them.

What is TypeScript?

TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale. It was developed by Microsoft and has since become one of the most popular languages for web development.

Here is the model to carry through the whole course, because almost everything else follows from it: TypeScript is a checking pass that runs before your code does, and then gets out of the way. The compiler reads your annotations, decides whether the program is consistent with them, and then erases them — what actually executes is plain JavaScript with the types stripped out.

That single fact lets you predict things you have not been shown yet. Ask of any TypeScript feature: is this a description, or is it a value? A description is checked and then vanishes, so it can never be consulted while the program runs — which is why you cannot ask at runtime "is this variable still a string?", and why a wrong type causes no crash of its own, only whatever the underlying JavaScript would have done anyway. The exceptions are the handful of features listed in the summary above (enum, decorators, namespaces, constructor parameter properties), which do emit real JavaScript because they create values, not just descriptions.

Key Features

Type Safety

function greet(name: string): void {
  console.log(`Hello, ${name}!`);
}

// This works: the argument is a string, which is what greet promised to take.
greet("TypeScript");

The annotation name: string is a promise, and the compiler is what holds you to it. Here is what breaking that promise looks like. This fence is marked no-run because its whole point is to fail to compile — the Run button strips the types and executes the result, so running it would print something and quietly contradict the lesson:

function greet(name: string): void {
  console.log(`Hello, ${name}!`);
}

greet(42);

Checked with tsc --strict, that program is rejected before it runs, with this exact message:

error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.

This course assumes strict mode throughout — the setting that turns on TypeScript's full checking. Every diagnostic you see in these lessons was produced with it on.

Now the part that surprises people, and it is worth meeting on day one. The type checker and the thing that runs your code are two separate tools. Below is the same call, forced past the compiler, so you can see what the running program actually does with it:

function greet(name: string): void {
  console.log(`Hello, ${name}!`);
}

greet("TypeScript");
greet(42 as unknown as string);

It prints Hello, TypeScript! and then Hello, 42! — no error, no crash. Nothing at runtime checks the type, because by then the types are gone. The compiler is the only thing that would have caught it, which is exactly why you run it.

Type Inference

TypeScript can automatically infer types, making your code cleaner while maintaining safety:

let x = 5;

let numbers = [1, 2, 3, 4, 5];

console.log(`x is ${x}`);
console.log(`numbers: ${numbers}`);

Neither line carries an annotation, and that is the point of the shape: write the annotation where it adds information, leave it off where the value already says everything. let x = 5 could be written let x: number = 5, but the 5 has already told both you and the compiler what this is, so the annotation only repeats it. Where annotations earn their place is on the boundaries — function parameters, return types, and data arriving from outside your program — because there the value is not visible at the point you are reading.

Predict

No annotation is written here — TypeScript infers the type from the value. What type does the compiler infer for x?

let x = 5;
Continue learning

Debug

This adds a score of 90 to a bonus of 10 and checks the result is 100. It runs without any complaint from the compiler and still fails its own check, with a value that is not the sum of anything. Commit a hypothesis about what the plus sign is actually doing here, then fix it so the total comes out as 100.

import assert from "node:assert";

const raw: any = { score: "90", bonus: 10 };

function finalScore(entry: any): number {
return entry.score + entry.bonus;
}

const total = finalScore(raw);
assert.strictEqual(total, 100, "a score of 90 plus a bonus of 10 should be 100, got " + total);
console.log("final score:", total);

Expected output:

final score: 100
Continue learning

Why Learn TypeScript?

  1. Code that states its own intent: an annotation records what a value is supposed to be, so the next reader — often you, months later — does not have to reconstruct it from the surrounding code
  2. Changes you can make with confidence: rename a field or change a shape and the compiler points at every place that assumed the old one, which is what makes a large codebase safe to reorganise
  3. Better editor support: autocomplete, go-to-definition and refactoring all work from the same type information you wrote
  4. Widely adopted: React, Angular, Vue and Node.js all ship TypeScript type definitions

A note on what to expect, because the claim is often overstated. The clearest documented benefits of static typing are clarity and maintainability — code that is easier to read, understand and change. Whether it reduces the number of bugs that reach production is genuinely contested in the research: some studies find a measurable share of faults are detectable by types, others find no improvement in bug-proneness while still finding clear gains in understandability. Treat TypeScript as a tool for making intent explicit and change safe, not as a guaranteed defect count.

Once you have the basics, the real power comes from TypeScript's structural type system — see Interfaces and Types and Generics to understand how to model any data shape safely.

Getting Started

To start coding in TypeScript, you'll need to:

  1. Write TypeScript code with type annotations
  2. Understand basic types (string, number, boolean, etc.)
  3. Learn how to compile TypeScript to JavaScript
  4. Practice with interactive examples

We'll cover each of these topics in detail in the upcoming lessons.

Interactive Playground

Practice what you've learned! Edit and run the code below to experiment with TypeScript. Most of it is written out for you to read; the last declaration is left as a TODO, so run it once to see what a missing value looks like, then fill it in and run it again.

// Try changing these values!
const language: string = "TypeScript";
const year: number = 2024;
const isAwesome: boolean = true;

// String formatting in TypeScript
console.log(`Learning ${language} in ${year}!`);
console.log(`Is TypeScript awesome? ${isAwesome}`);

// Working with arrays
const numbers: number[] = [1, 2, 3, 4, 5];

// TODO: the declarations above each pair a value with its type, and they are
// written out for you. This one is not. `doubled` should hold every number in
// `numbers` multiplied by two — numbers.map(x => x * 2) produces exactly that.
// Replace the empty list; until you do, the last line prints nothing after the
// colon.
const doubled: number[] = [];

console.log(`Original numbers: ${numbers}`);
console.log(`Doubled numbers: ${doubled}`);

Arrange the code

These four lines declare a course name, shout it, measure it, and report the result. The pieces are shuffled. Put them back in an order that runs — then answer what the puzzle is really testing: which line could not have moved, and what does the runner do if it does?

  1. console.log(`${shouted} has ${letters} letters`);
  2. const language: string = "TypeScript";
  3. const letters = shouted.length;
  4. const shouted = language.toUpperCase();
Continue learning

Transfer

A JavaScript function that needs a string often defends itself at the top of its body, with something like a typeof check that throws when the argument is wrong. A TypeScript function writes name: string in the signature instead. Both are ways of insisting on a string. The same question is being answered in two places. Which statement names what actually differs?

Continue learning

Reading about types is not the same as working with them. This is a build task: a small program that reports its own pass/fail. You are given two fixed values — a course name and a lesson count — and three unfinished const declarations, each leaning on something this lesson showed you: a string method, a template literal, and a comparison that yields a boolean. Run it as-is and it fails immediately, naming the first value that is still wrong. Fill each one in until every check passes and it prints All checks passed.

Build

Finish the build. Three const declarations start out as undefined placeholders, and the checks below them fail until each one holds the right value. Run it as-is to see which check fails first, work out what that value should be, then replace each placeholder in turn until it prints 'All checks passed.' The checks run top to bottom, so the first failure you see is TODO 1 - fix that one first, then work down.

import assert from "node:assert";

// The data: a course to describe. Do NOT change these.
const courseName: string = "TypeScript";
const lessonCount: number = 25;

// TODO 1: the course name in upper case.
//   "TypeScript" -> "TYPESCRIPT"
const shouted: string | undefined = undefined; // replace undefined with your code

// TODO 2: a sentence built with a template literal.
//   "TypeScript" and 25 -> "TypeScript has 25 lessons"
const blurb: string | undefined = undefined; // replace undefined with your code

// TODO 3: whether the course has more than 10 lessons, as a boolean.
//   25 > 10 -> true
const isLong: boolean | undefined = undefined; // replace undefined with your code

// --- Build checks: Do not edit below this line. ---
assert.strictEqual(shouted, "TYPESCRIPT", "shouted should be the course name in upper case");
assert.strictEqual(blurb, "TypeScript has 25 lessons", "blurb should combine the name and the lesson count into one sentence");
assert.strictEqual(isLong, true, "isLong should be a boolean for whether lessonCount is greater than 10");
assert.strictEqual(typeof isLong, "boolean", "isLong should be a real boolean, not a string or a number");

console.log("All checks passed.");
console.log("Shouted:", shouted);
console.log("Blurb:", blurb);
console.log("Is long:", isLong);

Expected output:

All checks passed.
Shouted: TYPESCRIPT
Blurb: TypeScript has 25 lessons
Is long: true
Continue learning

Once it passes, try two variations and predict each before running:

  1. A truthy value that is not a boolean. Change isLong to `${lessonCount > 10}` — the same comparison, wrapped in a template literal so it becomes the string "true". Before running, decide which of the two isLong checks breaks and which one passes. The strict-equality check fails first, because the string "true" is not the boolean true; this is why the fourth check exists at all.
  2. Off-by-one on the boundary. Change the comparison in isLong to lessonCount > 25. Predict the result before you run it. lessonCount is exactly 25, and > is strictly greater than, so this is false and the check fails — the boundary case that separates > from >=.

Recall

Without scrolling up: this lesson ran a call that the compiler rejects, forced past it, and the program printed a greeting instead of failing. What happens to your type annotations between writing the code and running it?

Continue learning

Key Takeaways

  • TypeScript adds a type layer on top of JavaScript — your existing working JS is TypeScript code, though under --strict it may not type-check until you annotate it
  • Type annotations (: string, : number) catch errors at compile time, before your code runs
  • TypeScript infers types automatically when the value makes the type obvious
  • The language is widely adopted by React, Angular, Vue, and Node.js ecosystems

Next Steps

Now that you know what TypeScript is and why it matters, it's time to explore the building blocks: how to declare variables and use TypeScript's core type system.

Ready to continue? Head to Variables and Types!

Two-tier handoff: this document is the complete reading surface. Continue learning for stateful practice, progress, and real sandbox execution.