cf.completefrontend
Open lab My progress
THE TYPESCRIPT FIELD GUIDE

Why TypeScript?

See which JavaScript mistakes TypeScript catches as you type, how it helps your editor, and what it can't check, with a cart you can edit and break.

By the end, you can
  • 01
    Say what TypeScript addsDescribe TypeScript as JavaScript plus types, which are checked before the code runs and removed after.
  • 02
    Read what it catchesSpot the mistakes TypeScript reports as you type, read its error messages in plain words, and use its editor help.
  • 03
    Know its limitsExplain what TypeScript can't check, like data that arrives while the page runs, and what it costs to use.

A bug caught before anyone sees it

A shop page adds up a cart. Tea costs 3 and cake costs 4, so the total should be 7. But the cake's price came from a form, and a form gives you text, not a number. Here is what plain JavaScript does with that:

A price that arrives as textPop out in the code editor (opens in a new tab)JavaScript
const teaPrice = 3;
const cakePrice = "4"; // typed into a form, so it's text
console.log(teaPrice + cakePrice);

Line 1 stores the number 3. Line 2 stores "4" in quotes, which is text. Line 3 adds them and prints 34. When one side of + is text, JavaScript joins the two instead of adding them (the Type conversion lesson explains why). Nothing warns you. The first person to notice might be a shopper looking at a total of $34.

TypeScript lets you say what kind of value each name should hold. That kind is called a type. Here is the same code with two types added:

The same price, with types (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const teaPrice: number = 3;const cakePrice: number = "4";console.log(teaPrice + cakePrice);

Line 1 says teaPrice is a number, and it is. Line 2 says cakePrice is a number too, but gives it text. TypeScript marks line 2 with an error, on purpose here, because it's the bug:

  • Type 'string' is not assignable to type 'number' means "you're putting text where a number has to go". A string is text, and "assignable" means "allowed to be stored there".
  • ts(2322) is the error's number. Every TypeScript error has one, so you can look it up.

The list under the code comes from the real TypeScript compiler, running in this page. Point at a name to see its type. Now try it yourself: type a different value for the cake's price, and watch the list under the code as you type.

Playground: type the cake's price
Tea and cake pricesPop out in the code editor (opens in a new tab)TypeScript
const teaPrice: number = 3;const cakePrice: number = "4";console.log(teaPrice + cakePrice);
Line 2 holds"4"
What happens
TypeScript1 error: line 2
When it runsprints 34
Try it yourself

Line 2 puts the text "4" where a number has to go, so TypeScript marks it: Type 'string' is not assignable to type 'number'. When it runs, 3 + "4" joins the two and prints 34.

The code is checked by the real TypeScript compiler each time you type. Only line 2 changes. Reset puts the text "4" back.

With 4 or Number("4"), line 2 holds a number, so the error disappears. Put the quotes back and it returns. true and four get errors of their own, and an empty box gets Expression expected, because line 2 needs a value. Every TypeScript example in this lesson works the same way: press Edit & run, change the code, and the errors update as you type.

Left, with TypeScript: an editor shows the line cakePrice: number = "4" and the note "text is not a number", found while you type. Right, plain JavaScript: a shop page shows Total: $34, found by a shopper.With TypeScripteditorcakePrice: number = "4"text is not a numberfound while you typePlain JavaScriptshopTotal: $34what the shopper seesfound by a shopper
The same mistake, two places to find it. With TypeScript, the editor marks line 2 while you type. Without it, the code runs and a shopper sees a total of $34.
Real-life analogyA spell checker for your code

When you type a letter on a computer, a spell checker underlines "recieve" the moment you write it. You fix it right there, long before anyone reads the letter. The underlines help you while you write, and they never appear on the paper.

In real life: You write a letter
In TypeScript: You write your code
In real life: The spell checker underlines a wrong word as you type
In TypeScript: TypeScript marks a wrong type as you type
In real life: You fix the word before you post the letter
In TypeScript: You fix the code before a shopper sees it
In real life: The underlines aren't printed on the letter
In TypeScript: The types are removed before the browser runs the code
The main idea

TypeScript is JavaScript plus types. A type says what kind of value a name must hold, like cakePrice: number. TypeScript checks your code against its types while you type and points at mistakes. Then it removes the types, so the browser runs plain JavaScript.

JavaScript with types

TypeScript isn't a new language you have to learn from the start. Almost any JavaScript is already TypeScript. Here is plain JavaScript, with no types written at all, checked by TypeScript:

Plain JavaScript is TypeScript tooPop out in the code editor (opens in a new tab)TypeScript
const user = { name: "Asha", cartItems: 2 };const greeting = `${user.name} has ${user.cartItems} items`;//    ^?console.log(greeting);

Line 1 makes a user object with a name and a number of cart items. Line 2 builds a message from them with a template literal. Line 4 prints Asha has 2 items. There are no errors.

Line 3 is a comment, so it changes nothing when the code runs. In this lesson a comment like // ^? asks a question: "what type is the name my ^ points at?" The page writes TypeScript's answer after it: const greeting: string. You never wrote string. TypeScript worked it out from the value, which is called inference. In your own editor, you get the same answer by pointing at the name.

When you want to say a type yourself, you write a colon and the type after a name. This is called a type annotation. Functions are where you'll write them most:

A function that takes two numbersPop out in the code editor (opens in a new tab)TypeScript
function lineTotal(price: number, quantity: number) {  return price * quantity;} const total = lineTotal(3, 2);//    ^?console.log(total);

Line 1 says lineTotal takes a price that is a number and a quantity that is a number. Line 2 multiplies them. Line 5 calls it with 3 and 2. The query on line 6 shows that TypeScript knows total is a number, without an annotation on line 5. Line 7 prints 6.

Browsers can't run price: number; it isn't JavaScript. So TypeScript does two jobs. First it checks the types. Then it removes them, and what's left is plain JavaScript. The program that does this is the TypeScript compiler, called tsc. Here is what it gives the browser for the example above:

A file cart.ts holds lineTotal(price: number, quantity: number). An arrow labelled 1, check the types, and 2, remove them, leads to a file cart.js holding lineTotal(price, quantity), which the browser runs.cart.tslineTotal(price: number,quantity: number)you write this1. check the types2. remove themcart.jslineTotal(price,quantity)the browser runs this
You write cart.ts with its types. TypeScript checks the types, then removes them. The browser runs cart.js, the same code without the types.
What the browser gets: the same code without typesPop out in the code editor (opens in a new tab)JavaScript
function lineTotal(price, quantity) {
  return price * quantity;
}

const total = lineTotal(3, 2);
console.log(total);

Line 1 has lost its two : number annotations. The rest is the same code, and it still prints 6. The query comment is left out here: it only asked TypeScript a question, and a comment does nothing when the code runs. The next lesson, How TypeScript works, follows this step closely.

The table below compares the two. Read each row as a question, then each language's answer.

JavaScript and TypeScript, side by side
QuestionJavaScriptTypeScript
What does the file name end in?.js, like cart.js..ts, like cart.ts.
Can you write a type, like price: number?No. That line is a syntax error in JavaScript.Yes. Types are the part TypeScript adds.
When do you find a wrong type?When the code runs and something goes wrong, maybe for a user.As you type, before the code runs.
What does the browser run?Your code, as you wrote it.Plain JavaScript: your code with the types removed.

Bugs caught while you type

The price bug from the start of the lesson is one of many mistakes TypeScript points at before your code runs. Try it on a whole cart. The code has a type alias on line 1: type CartItem = … gives a name to the shape every cart item must have, a name that is text and a price that is a number. Line 3 says cart is a list of those items.

Playground: what the Cake price is
A cart of tea and cakePop out in the code editor (opens in a new tab)TypeScript
type CartItem = { name: string; price: number }; const cart: CartItem[] = [  { name: "Tea", price: 3 },  { name: "Cake", price: 4 },]; let total = 0;for (const item of cart) {  total += item.price;}console.log(`Total: $${total}`);
What the shopper seesTotal: $7
What happens
Cake price4
TypeScriptNo errors
Try it yourself

Line 5 gives Cake the number 4. Every price is a number, so TypeScript has nothing to report, and the cart prints Total: $7.

TypeScript checks the code for real, and the total is what this code prints. Each button changes only line 5. Reset goes back to A number.

Press each button and watch the list under the code. With A number, there are no errors and the total is $7. Text from a form puts "4" on line 5: the error appears, and the shopper would see $34. Text, converted wraps it in Number(…), which turns text into a number, and the error disappears. Price left out gets Property 'price' is missing, because every CartItem needs a price; the shopper would see NaN, which means "not a number". You can also press Edit & run and type any price you like on line 5.

Here are three more mistakes. Each one gets its error on purpose. First, a misspelled property:

A misspelled property (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const cart = { items: 2, total: 7 };console.log(cart.totl);

Line 1 makes a cart with items and total. Line 2 asks for cart.totl. TypeScript knows the cart has no totl, and its message even suggests the fix: Did you mean 'total'? Plain JavaScript would print undefined.

A forgotten argument (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
function applyDiscount(total: number, percent: number) {  return total - (total * percent) / 100;}console.log(applyDiscount(20));

Line 1 says applyDiscount takes a total and a percent. Line 2 takes the percent off the total. Line 4 calls it with only 20. TypeScript says Expected 2 arguments, but got 1. Plain JavaScript would use undefined for the missing percent and print NaN.

A product that isn't in the cart (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const cart = [{ name: "Tea", price: 3 }];const cake = cart.find((item) => item.name === "Cake");console.log(cake.price);

Line 1 makes a cart with only tea. Line 2 uses find, which gives back the first item that matches, or undefined when none does (Searching arrays covers it). There's no cake, so cake is undefined. Line 3 reads its price. When this runs, JavaScript throws a TypeError and the code stops. TypeScript saw it coming: 'cake' is possibly 'undefined'.

The table below puts the four mistakes side by side. Read each row as: this mistake, then what each language does about it.

Four mistakes, with and without TypeScript
The mistakePlain JavaScriptTypeScript
A price arrives as text: price: "4"It prints Total: $34. Nothing warns you.Line 5 gets an error: Type 'string' is not assignable to type 'number'.
A misspelled property: cart.totlIt prints undefined.An error that also suggests the fix: Did you mean 'total'?
A missing argument: applyDiscount(20)It prints NaN, which means "not a number".An error: Expected 2 arguments, but got 1.
A product that isn't in the cart: cake.priceIt throws a TypeError, and the code stops.An error: 'cake' is possibly 'undefined'.

Editor help: autocomplete and rename

Because TypeScript knows the type of every value, your editor can use that knowledge while you write. Editors like VS Code ask TypeScript about your code all the time, even in plain .js files. Here is what TypeScript knows about one object:

TypeScript knows the shape of an objectPop out in the code editor (opens in a new tab)TypeScript
const settings = { theme: "dark", fontSize: 16, showTips: true };//    ^?settings.fontSize = 18;

Line 1 makes a settings object for a page: a theme, a font size, and whether to show tips. The query on line 2 shows the type TypeScript worked out: theme is a string, fontSize is a number, and showTips is a boolean (true or false). Line 3 changes the font size to 18, which is fine because 18 is a number.

That type is how autocomplete works. When you type settings., the editor lists the three properties, so you pick a name instead of remembering how to spell it:

An editor window. After typing settings and a dot, a list opens under it with fontSize, showTips, and theme. A note says TypeScript knows what settings has.editorsettings.fontSizeshowTipsthemeTypeScript knowswhat settings has
You type settings. and the editor lists the three properties settings has. It knows them from the type TypeScript worked out on line 1.

The same knowledge makes renaming safe. Say you decide price should be called unitPrice. In plain JavaScript, you search for every price and hope you found them all. With TypeScript, change the name in the type, and every place still using the old name gets an error. Step through a rename:

Playground: rename price to unitPrice
A cart with a price to renamePop out in the code editor (opens in a new tab)TypeScript
type CartItem = { name: string; price: number }; const tea: CartItem = { name: "Tea", price: 3 };const cake: CartItem = { name: "Cake", price: 4 }; function lineTotal(item: CartItem, quantity: number) {  return item.price * quantity;} console.log(lineTotal(tea, 2) + lineTotal(cake, 1));
Console output10
What happens
TypeScriptNo errors
Step 1 of 4

Every line says price. TypeScript has no errors, and the order costs 10: two teas at 3 and one cake at 4.

TypeScript checks the code for real at every step, and the output is what the code prints. Reset goes back to step 1.

Step 2 changes only line 1, and TypeScript lists lines 3, 4, and 7: a to-do list of places to update. Step 3 updates the two objects, and only line 7 is left. That is the dangerous moment in plain JavaScript: the objects say unitPrice, line 7 reads price, and the order quietly costs NaN. Step 4 fixes line 7, and the errors are gone. In VS Code, the Rename Symbol command (the F2 key) does all of this in one go, because it uses the same types.

What TypeScript doesn't do

TypeScript checks your code before it runs. Once it has removed the types, its job is done. So it can't check anything that only exists while the page runs, like a reply from a server:

A server reply with a price as textPop out in the code editor (opens in a new tab)TypeScript
type Product = { name: string; price: number }; const reply = '{ "name": "Cake", "price": "4" }';const cake: Product = JSON.parse(reply);//    ^?console.log(cake.price + 3);

Line 1 describes a Product: a name and a number price. Line 3 is the reply as the server sent it, and its price is the text "4". Line 4 turns the reply into an object with JSON.parse and says it's a Product. The query on line 5 shows TypeScript believes you: const cake: Product. There are no errors, but line 6 prints 43, because the price is really text.

JSON.parse can give back anything, so TypeScript can't know what's inside. It trusts the type you wrote. (The JSON lesson covers JSON.parse itself.)

A server window sends a card that says price is the text 4. An arrow, marked no type check here, carries it to a browser window, where cake.price + 3 gives 43.server"price": "4"the price is textno typecheck herebrowsercake.price + 3"43""43", not 7
The reply arrives while the page runs, after the types are gone. Nothing checks it, so the text "4" reaches cake.price + 3 and makes "43".
Real-life analogyA recipe checker can't taste the eggs

A friend reads your recipe card before you cook and spots that you wrote "2 cups of salt". That's useful. But your friend never sees the eggs that are delivered on the day. If they're bad, you only find out when you open the box.

In real life: A friend checks your recipe card
In TypeScript: TypeScript checks your code
In real life: "Two eggs" is written correctly
In TypeScript: price: number is written correctly
In real life: The eggs delivered on the day
In TypeScript: The reply that arrives while the page runs
In real life: You still look at the eggs when they come
In TypeScript: You still check the reply with code, like Number(data.price)

TypeScript also can't tell that a calculation is wrong when every type is right:

A wrong sum with the right typesPop out in the code editor (opens in a new tab)TypeScript
function lineTotal(price: number, quantity: number) {  return price + quantity;}console.log(lineTotal(3, 2));

Line 2 should multiply the price by the quantity, but it adds. Both are numbers, so every type is right, and line 4 prints 5 instead of 6 with no error. Tests, and trying your page, find this kind of mistake.

The table below lists jobs you might expect from TypeScript. Read each row as: this job, does TypeScript do it, and why.

What TypeScript does, and what it doesn't
The jobDoes TypeScript do it?Why
Point at a wrong type while you typeYes.It reads your code and compares each value with the type it should have.
Check data from a server, a form, or storage while the page runsNo.The types are removed before the code runs, so nothing is left to check with.
Find a wrong calculation, like + where you meant *No.Both sides are numbers, so every type is right. Tests find this kind of mistake.
Make your code run fasterNo.The browser runs the same JavaScript either way.
Change what your code doesNo.Your code does exactly what it would do as plain JavaScript.

TypeScript also has costs. They're worth knowing before you start:

  • A build step: something has to remove the types before the browser runs your code.
  • New things to learn: the type syntax, and how to read the error messages.
  • Time spent writing types, mostly for data that comes from outside, like server replies.
  • Now and then, code you know is right needs a small change before TypeScript accepts it.

For most frontend projects, the bugs it catches early are worth that cost, which is why so many teams use it.

A quantity box on a checkout page

On a real checkout page, the shopper types how many cakes they want into a box. The page reads the box with .value, and adds one when they press a plus button. TypeScript already knows the browser's own types, like what an <input> element holds:

A quantity read from a text box (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const quantityInput = document.createElement("input");quantityInput.value = "2"; const quantity = quantityInput.value;//    ^?const nextQuantity: number = quantity + 1;console.log(nextQuantity);

Line 1 makes an <input> text box, and line 2 puts "2" in it, as if the shopper typed 2 (Form elements covers inputs and .value). Line 4 reads the value. The query on line 5 shows it's a string: a text box always gives text. Line 6 adds 1 and says the result must be a number. TypeScript marks line 6, because text plus 1 is text. Run it anyway and it prints 21.

The quantity turned into a numberPop out in the code editor (opens in a new tab)TypeScript
const quantityInput = document.createElement("input");quantityInput.value = "2"; const quantity = Number(quantityInput.value);//    ^?const nextQuantity: number = quantity + 1;console.log(nextQuantity);

The only change is line 4: Number(quantityInput.value) turns the text into a number as it comes in. The query on line 5 now says number, the error is gone, and line 7 prints 3. Converting outside data once, at the point it arrives, is the habit TypeScript pushes you toward.

Error or fine?
  • const price: number = "4";
  • const price: number = Number("4");
  • const cart = { total: 7 }; console.log(cart.totl);
  • const cart = { total: 7 }; console.log(cart.total);
  • Math.round("4.5");
  • const quantity = 2; quantity.toUpperCase();
  • const reply: { price: number } = JSON.parse('{"price":"4"}');
  • const label = "Total: " + 7;
Try it yourself
0 of 8 correct

Sort each line by what TypeScript says about it. Each line is checked on its own.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common mix-ups

TypeScript only catches a wrong type when it knows the right one. Here is the price bug again, with no types written:

The price bug with no types writtenPop out in the code editor (opens in a new tab)TypeScript
const teaPrice = 3;const cakePrice = "4";console.log(teaPrice + cakePrice);

Line 1 makes teaPrice a number, and line 2 makes cakePrice a string. Line 3 joins them and prints 34, and TypeScript reports nothing. Joining text with + is allowed, and often exactly what you want. The overview caught the bug only because line 2 said cakePrice must be a number.

  • "TypeScript is a different language from JavaScript." No. It's JavaScript with types added. The browser runs the JavaScript that's left when the types are removed.
  • "TypeScript checks my data while the page runs." No. The types are gone by then. A server reply with a price as text gets through, as the 43 example showed.
  • "No errors means no bugs." No. A sum with + where you meant * has the right types and the wrong answer.
  • "I have to write a type on every variable." No. TypeScript works out most types from the values, like const total: number. You write types mostly for function parameters and outside data.
  • "A type error stops my code from running." No. The overview's typed example still prints 34 when you run it. The error is a warning for you. The next lesson shows what the compiler does with code that has errors.
  • "TypeScript makes my code faster." No. The browser runs the same JavaScript either way.

Practice exercises

Each exercise is TypeScript. When you fix code, press Edit & run on the starter code: the errors update as you type, and the console shows what it prints. Try a guess first, then use the hints.

Exercise 1 · Warm-upFind the line TypeScript marks

Two cart items, one with a mistake. Which line will TypeScript mark?

Starter codePop out in the code editor (opens in a new tab)TypeScript
type CartItem = { name: string; price: number };

const tea: CartItem = { name: "Tea", price: 3 };
const cake: CartItem = { name: "Cake", price: "4" };

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · Warm-upRead a worked-out type

    No types are written here. What type does TypeScript give paid? Guess first. Then point at paid to check, or press Edit & run and add a // ^? line under it.

    Starter codePop out in the code editor (opens in a new tab)TypeScript
    const order = { id: 7, paid: false };const paid = order.paid;

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFix a price that arrives as text

      TypeScript marks line 5. Fix it so the cart holds two numbers. What does the fixed code print?

      Starter codePop out in the code editor (opens in a new tab)TypeScript
      type CartItem = { name: string; price: number }; const cart: CartItem[] = [  { name: "Tea", price: 3 },  { name: "Cake", price: "4" },]; console.log(cart[0].price + cart[1].price);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeFix the typo TypeScript found

        A settings object and a typo. Fix line 3. Which name should it use?

        Starter codePop out in the code editor (opens in a new tab)TypeScript
        const settings = { theme: "dark", fontSize: 16 }; console.log(settings.fontsize);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeSpot what TypeScript can't see

          A server sends a product. TypeScript is happy with the code. What does it print? Then change it so the price really is a number.

          Starter codePop out in the code editor (opens in a new tab)TypeScript
          type Product = { name: string; price: number }; const reply = '{ "name": "Tea", "price": "3" }';const tea: Product = JSON.parse(reply);console.log(tea.price * 2 + tea.price);

          Answer, then press Check. Spacing and letter case don’t matter.

            Exercise 6 · ChallengeHandle a product that isn't there

            This code throws a TypeError when it runs, and TypeScript warned about it. What does find give back when nothing matches? Then fix the code so it prints a message instead.

            Starter codePop out in the code editor (opens in a new tab)TypeScript
            const cart = [{ name: "Tea", price: 3 }];const cake = cart.find((item) => item.name === "Cake");console.log(cake.price);

            Answer, then press Check. Spacing and letter case don’t matter.

              Check your understanding

              For each question, keep two moments apart: what TypeScript says before the code runs, and what the code does when it runs. The quiz shows its code without the checker, so the error list doesn't give the answers away.

              The Why TypeScript? quiz · 7 questionsScore: first tries count
              1. Question 1 of 7Which sentence describes TypeScript best?

                Choose an answer to see the explanation.

              2. Question 2 of 7Which line does TypeScript flag in this order?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                type Order = { item: string; quantity: number };
                
                const order: Order = { item: "Tea", quantity: 2 };
                order.quantity = "3";

                Choose an answer to see the explanation.

              3. Question 3 of 7This code has a type error. What does it print when it runs anyway?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const items: number = 2;
                const extra: number = "1";
                console.log(items + extra);

                Choose an answer to see the explanation.

              4. Question 4 of 7Does TypeScript report an error for this server reply, and what prints?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                type User = { name: string; age: number };
                
                const user: User = JSON.parse('{ "name": "Asha", "age": "30" }');
                console.log(user.age + 1);

                Choose an answer to see the explanation.

              5. Question 5 of 7What type does TypeScript show when you hover total on line 1?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                let total = 0;
                total = total + 3;

                Choose an answer to see the explanation.

              6. Question 6 of 7Which job does TypeScript NOT do for you?

                Choose an answer to see the explanation.

              7. Question 7 of 7What does this order total print, and does TypeScript complain?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                function orderTotal(price: number, quantity: number) {
                  return price + quantity;
                }
                console.log(orderTotal(4, 3));

                Choose an answer to see the explanation.

              Key takeaways

              • TypeScript is JavaScript plus types. A type says what kind of value a name must hold, like price: number.
              • It points at wrong types while you type: text where a number goes, a misspelled property, a missing argument, a value that may be undefined.
              • You don't write every type. TypeScript works most of them out, and you can see them by pointing at a name.
              • Your editor uses the types for autocomplete and for renaming safely.
              • The types are removed before the browser runs the code, so data that arrives while the page runs isn't checked.
              • It can't find a wrong calculation with the right types, and it doesn't make code faster.

              Remember the one-liner.
              TypeScript checks your types while you write, then steps aside, and the browser runs plain JavaScript.

              Coming next: How TypeScript works. It follows your code through the compiler: checking, removing the types, and why code with errors still runs.

              CompleteFrontend Clear concepts. Working examples.