cf.completefrontend
Open lab My progress
THE TYPESCRIPT FIELD GUIDE

Reading TypeScript Errors

Read TypeScript's error messages: the error number, the chain of reasons read from the bottom up, the common errors and fixes, and where the red line lands.

By the end, you can
  • 01
    Read one errorFind where it is, what it says you gave and what the place needs, and what its number means.
  • 02
    Read a long errorStart at the last line of a chain to find the real mismatch, and use the lines above it as the path.
  • 03
    Find the real mistakeFix the common errors, and move an error to its cause with an annotation, a split line, or a named type.

What a type error tells you

A signup form asks for an email and an age. The age arrives from a text box, so it's still text. TypeScript marks it, on purpose here:

A signup form with the age as text (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type SignupForm = { email: string; age: number }; const form: SignupForm = {  email: "asha@example.com",  age: "30",};console.log(form.age);

Line 1 says a SignupForm has an email that is a string (text) and an age that is a number. Lines 3 to 6 make a form with that type. Line 5 gives the age the text "30", and that's the line TypeScript marks. Line 7 still prints 30 when the code runs, because a type error doesn't stop the code.

Look at the list under the code. The error has three parts:

  • Where: Line 5. In the code, a red wavy line, the squiggle, sits under age.
  • What: Type 'string' is not assignable to type 'number'. "Assignable" means "allowed to be stored there". So it says: you gave a string, and this place needs a number.
  • Which number: ts(2322). Every kind of TypeScript error has a number.
An error from the list under the code, cut into three cards: Line 5, the message Type 'string' is not assignable to type 'number', and ts(2322). Under them: where, what went wrong, and its number. Under the message: string is what you gave, number is what age needs.Line 5Type 'string' is not assignable to type 'number'.ts(2322)wherewhat went wrongits number'string'what you gave'number'what age needs
The error on line 5 in three parts. Inside the message, the first type is what you gave, the text "30". The second is what age needs.

Many errors are longer. Under the first line they add more lines, each pushed a little to the right. Each of those lines says why the line above it is true. This lesson shows you how to read them, which errors you'll see most, and what to do when the red line isn't where the mistake is.

Real-life analogyA parcel that comes back

You post a parcel, and it comes back with a note. The first line says "Parcel returned". That's true, but it doesn't help. The line under it says "Address not accepted". The last line says "No house number 12 on Oak Street". That's the line you act on: you fix the house number. The reference number at the top lets you ask the courier about it.

In real life: The note's first line: "Parcel returned"
In TypeScript: The first line: Type 'ApiCart' is not assignable …
In real life: Each line under it says why: "Address not accepted"
In TypeScript: Each indented line says why about the line above
In real life: The last line: "No house number 12 on Oak Street"
In TypeScript: The last line: Type 'string' is not assignable to type 'number'
In real life: A reference number you can quote on the phone
In TypeScript: ts(2345), a number you can search for
The main idea

A type error says where, what, and which number. The message reads "what you gave" first and "what the place needs" second. A long error is a chain of reasons: the first line is the summary, and the last line is usually the real mismatch. The red line shows where TypeScript noticed, which isn't always where the mistake is.

Where, what, and which number

Change the age yourself and watch the message. Type a new value for line 5. The list under the code updates as you type:

Playground: type the age
A signup form's agePop out in the code editor (opens in a new tab)TypeScript
type SignupForm = { email: string; age: number }; const form: SignupForm = {  email: "asha@example.com",  age: "30",};console.log(form.age);
Line 5 holds"30"
What happens
TypeScript1 error: line 5
Error numberts(2322)
When it runsprints 30
Try it yourself

Line 5 gives age the text "30". The message is Type 'string' is not assignable to type 'number': you gave a string, and age needs a number.

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

With 30 or Number("30"), the value is a number, so the error is gone. With true the message says Type 'boolean' is not assignable to type 'number', and with null it says Type 'null' …. The first type changes with what you type. The second stays number, because the place still needs one. The number stays 2322, because it's still the same kind of mistake. An empty box gets a different number, 1109, and Expression expected: the line isn't finished, so there's nothing to check yet.

Here's how to read each part of an error:

The parts of one error, using the signup form. Read each row as: the part, what it tells you, and what to do with it.
The partWhat it tells youWhat to do with it
Line 5 (or signup.ts:5:3)Where TypeScript found the problem: the line, and in a terminal the column too.Start looking here, but the mistake may be somewhere else.
Type 'string'The type of what you gave: here, the text "30".Ask where that value came from.
type 'number'The type this place needs: here, the age: number in SignupForm.Ask whether the value or the type is wrong.
ts(2322)The error's number. The words change with your names, but the number doesn't.Search for TS2322 to find other people's answers.

The order matters. "Assignable" goes one way: a value of the first type must fit where the second type is needed. A number fits where number | null is needed, but number | null doesn't fit where only a number goes. (Structural typing explains how TypeScript decides what fits.)

A terminal shows the same error with a little more. How TypeScript works showed how to read the first lines. Here is the signup form saved as signup.ts and checked with npx tsc --noEmit:

What tsc prints for signup.tsText
signup.ts:5:3 - error TS2322: Type 'string' is not assignable to type 'number'.

5   age: "30",
    ~~~

  signup.ts:1:36
    1 type SignupForm = { email: string; age: number };
                                         ~~~
    The expected type comes from property 'age' which is declared here on type 'SignupForm'

Line 1 has the place, signup.ts:5:3 (file, line 5, column 3), then TS2322 and the message. Lines 3 and 4 show line 5 of the file with ~~~ under age. Lines 6 to 9 are a related note: it points at line 1 of the file and says The expected type comes from property 'age' which is declared here on type 'SignupForm'. That tells you where the number came from. If the type is the thing that's wrong, that's the line to change. Editors like VS Code list the same note under the error in their list of problems.

Long errors: read from the bottom up

A cart comes from a server. Its prices arrive as text, and showTotal wants a Cart with number prices. The error is six lines long, on purpose:

A server cart passed to showTotal (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type Item = { name: string; price: number };type Cart = { items: Item[]; total: number };type ApiCart = { items: { name: string; price: string }[]; total: number }; function showTotal(cart: Cart) {  console.log(`Total: $${cart.total}`);} const fromServer: ApiCart = { items: [{ name: "Tea", price: "3" }], total: 3 };showTotal(fromServer);

Line 1 says an Item has a number price. Line 2 says a Cart has a list of items and a total. Line 3 describes what the server sends, an ApiCart, where each price is a string. Lines 5 to 7 are showTotal, which takes a Cart. Line 9 makes the server's cart. Line 10 passes it to showTotal, and TypeScript marks the argument fromServer. It prints Total: $3 when it runs.

Here is the whole message, as the list under the code shows it:

The six lines of the errorText
Argument of type 'ApiCart' is not assignable to parameter of type 'Cart'.
  Types of property 'items' are incompatible.
    Type '{ name: string; price: string; }[]' is not assignable to type 'Item[]'.
      Type '{ name: string; price: string; }' is not assignable to type 'Item'.
        Types of property 'price' are incompatible.
          Type 'string' is not assignable to type 'number'.

The first line is the summary: the ApiCart doesn't fit where a Cart is needed. Each line under it is pushed further right, and answers "why?" about the line above. The TypeScript handbook calls these lines elaborations. Read them from the bottom up:

  1. Line 6, the last: Type 'string' is not assignable to type 'number'. This is the real mismatch: text where a number goes.
  2. Line 5: Types of property 'price' are incompatible. The text is a price.
  3. Lines 4 and 3: the price belongs to one item, and that item is in an array of items.
  4. Line 2: Types of property 'items' are incompatible. The array is the cart's items.

So the path is items, then one item, then price, and the problem is that it's text. Two fixes make sense: change ApiCart if the server really sends numbers, or turn each price into a number before calling showTotal.

Five cards step down to the right, one per reason: ApiCart isn't a Cart, its items don't fit, one item isn't an Item, its price doesn't fit, and string isn't number. An arrow goes up from the last card, marked start here and read up.ApiCart isn't a Cartits items don't fitone item isn't an Itemits price doesn't fitstring isn't numberwhy?why?why?start herereadup
The error under showTotal(fromServer), one card per reason. Each card answers "why?" about the card above it. The last card is the real mismatch: a price that is text.

Sometimes TypeScript shortens the path into one line. Break a server reply in different places and watch the middle line:

Playground: break the server's reply
A cart line from the serverPop out in the code editor (opens in a new tab)TypeScript
type Price = { amount: number; currency: string };type Product = { name: string; price: Price };type CartLine = { product: Product; quantity: number }; const reply = {  product: { name: "Tea", price: { amount: "3", currency: "USD" } },  quantity: 2,};const line: CartLine = reply;
The pathproduct.price.amount
What happens
TypeScript1 error: line 9
Last lineType 'string' is not assignable to type 'number'.
Try it yourself

The first line names the whole reply and CartLine. The middle line gives the path: The types of 'product.price.amount' are incompatible between these types. The last line says why: Type 'string' is not assignable to type 'number'. The amount "3" is text.

TypeScript checks the code for real. Each button changes lines 6 and 7. Whatever breaks, the error lands on line 9. Reset goes back to Amount as text.

With Amount as text, the middle line is The types of 'product.price.amount' are incompatible between these types: the whole path, written like the code you'd use to reach the value. Currency missing stops the path at product.price, and its last line is a different error, Property 'currency' is missing …. Whatever the chain says above, the last line tells you what to fix.

In the playground, the error lands on line 9, under the variable line, because reply was made first and stored later. Write the same object straight into the typed variable, and TypeScript can point at the exact property:

The same reply, written in place (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type Price = { amount: number; currency: string };type Product = { name: string; price: Price };type CartLine = { product: Product; quantity: number }; const line: CartLine = {  product: { name: "Tea", price: { amount: "3", currency: "USD" } },  quantity: 2,};

Line 5 says the object is a CartLine from the start. The squiggle is now under amount on line 6, and the message is one line: Type 'string' is not assignable to type 'number'. When TypeScript can mark the exact spot, it doesn't need a chain.

One error with two chains

Some functions can be called in more than one way. Each way is called an overload (Function overloads explains them). When no way fits, you get error 2769, with one chain per overload. Here a click listener expects a key, on purpose:

A click listener that reads a key (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
document.addEventListener("click", (event: KeyboardEvent) => {  console.log(event.key);});

Line 1 listens for "click" and says the event is a KeyboardEvent. Line 2 reads its key. The error is long. Point at the red line to read it. It has this shape:

  • No overload matches this call. The summary.
  • Overload 1 of 2, '(type: "click", …)', gave the following error. Then its chain, ending with Type 'PointerEvent' is missing the following properties from type 'KeyboardEvent': …
  • Overload 2 of 2, '(type: string, …)', gave the following error. Then a second chain about a plain Event.

Read the chain for the overload you meant. You wrote "click", so overload 1 is yours, and its last line says a click gives a PointerEvent, which has no key. Overload 2 is the general one for any event name; it's rarely the one you meant. If you wanted keys, listen for "keydown":

Listening for keys insteadPop out in the code editor (opens in a new tab)TypeScript
document.addEventListener("keydown", (event: KeyboardEvent) => {  console.log(event.key);});

Line 1 now listens for "keydown", which gives a KeyboardEvent, so there are no errors. (Typing events shows which event each name gives.)

The errors you'll meet most

A few error numbers make up most of what you'll see. In the table, X, Y, T, and p stand for the types and names from your code:

Common errors. Read each row as: the error number, the message, and what it usually means.
NumberThe messageWhat it usually means
2322Type 'X' is not assignable to type 'Y'.A value doesn't fit the type of the place you put it.
2345Argument of type 'X' is not assignable to parameter of type 'Y'.A value you pass to a function doesn't fit the parameter.
2339 (2551)Property 'p' does not exist on type 'T'.The type has no property with that name. 2551 adds Did you mean …? for a near miss.
18047, 18048'cart' is possibly 'null'. or … 'undefined'.The value may be missing. Check it before you use it.
2531, 2532Object is possibly 'null'. or … 'undefined'.The same, for a value with no simple name, like document.querySelector("input").
7006Parameter 'p' implicitly has an 'any' type.A parameter needs a type, and TypeScript can't work one out.
2741Property 'p' is missing in type 'X' but required in type 'Y'.An object has fewer properties than its type needs.
2353Object literal may only specify known properties, and 'p' does not exist in type 'T'.An object written in place has a property its type doesn't list.
2769No overload matches this call.None of the function's ways to be called fits. Each one gets its own chain.

Pick a number to see a small example, then switch to the fixed version:

Playground: one example per error number
ts(2322): A value doesn't fitPop out in the code editor (opens in a new tab)TypeScript
let total: number = 0;total = "7";console.log(total);
Errorts(2322)
What happens
TypeScript1 error: line 2
When it runsprints 7
Try it yourself

Type 'string' is not assignable to type 'number': line 2 stores text in total, which line 1 made a number. The fix stores the number 7.

Pick an error number, then switch between the code with the error and the fixed code. TypeScript checks both for real. Reset goes back to 2322.

A few things the examples show:

  • 2322 and 2345 are the same check in two places: storing a value, and passing it to a function. The second one says Argument and parameter.
  • 2741 and 2353 are opposites: a property the type needs is missing, or an extra one isn't in the type. 2353 only applies to an object written in place (Excess property checks explains why).
  • 18048 says 'cake' is possibly 'undefined'. With a value that may be null, it's 18047. When the value has no simple name, like document.querySelector("input").value, the message says Object is possibly 'null' instead (2531, or 2532 for undefined). null and undefined covers the fixes.
  • 7006 only appears when noImplicitAny is on, and strict turns it on. You get one error per parameter.

Where the red line lands

TypeScript marks the place where it finds that something doesn't fit. That's often not where you made the mistake. Here a function turns a name and an address into a user, with a typo:

Playground: move the error to the typo
Turning a name and an address into a UserPop out in the code editor (opens in a new tab)TypeScript
type User = { name: string; email: string }; function toUser(name: string, address: string) {  return { name, emial: address };} const asha: User = toUser("Asha", "asha@example.com");console.log(asha.email);
Console outputundefined
What happens
TypeScript1 error: line 7
Step 1 of 3

The typo is on line 4, but the red line is on line 7: Property 'email' is missing in type '{ name: string; emial: string; }' but required in type 'User'. toUser may return any object, so TypeScript only finds a problem where its result has to be a User.

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

At step 1, line 4 spells emial, but line 4 is fine as far as TypeScript knows: toUser has no return type, so any object can come back. The first place the result must be a User is line 7, so that's where the error is. It even says Property 'email' is missing, which is true but sends you looking in the wrong place.

At step 2, line 3 says : User, the type the function should return. Now TypeScript checks the object on line 4 against User, and the error moves there. It says Did you mean to write 'email'?. Writing the type you meant moves the error to the line that breaks it. (Annotations and inference covers return types.)

Left, no return type: an editor shows lines 3, 4 and 7 of toUser, and line 7, const asha: User, is marked. Right, with : User on line 3: the same lines, and line 4, with the typo emial, is marked.No return typeeditor3 toUser(…) {4 { name, emial }7 asha: User = …markedfar from the typoWith : Usereditor3 toUser(…): User {4 { name, emial }7 asha: User = …markedon the typo
The same typo on line 4. With no return type, TypeScript marks line 7, where the result must be a User. With : User on line 3, it marks line 4, the typo itself.

When the same error shows up in several places, look for what they share:

One mistake, two errors (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
type CartItem = { name: string; price: number }; function makeItem(name: string, price: string) {  return { name, price };} const cart: CartItem[] = [makeItem("Tea", "3"), makeItem("Cake", "4")];console.log(cart.length);

Line 3 says makeItem takes a price that is a string. Line 4 returns it. Line 7 calls makeItem twice, and both calls get the same error, ending in Type 'string' is not assignable to type 'number'. You could fix both calls, but the mistake is the one parameter type on line 3. Change it to price: number and pass 3 and 4, and both errors go. Line 8 prints 2 either way.

Investigate with your editor

Your editor knows every type in your code. When an error confuses you, ask it. Point at a name to see its type. In this lesson, a // ^? line asks the same question and writes the answer after it. Here is a long line with two errors in it:

Adding up a cart in one line (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const prices = new Map([["tea", 3], ["cake", 4]]);const cart = ["tea", "cake"];const total = cart.map((id) => prices.get(id)).reduce((sum, price) => sum + price, 0);console.log(total);

Line 1 makes a Map from product ids to prices. Line 2 is the cart, a list of ids. Line 3 turns each id into its price with map, then adds them up with reduce (map, filter, and reduce explains both). TypeScript marks sum and price on line 3: 'sum' is possibly 'undefined', and the same for price. But where does the undefined come from? Split the line into steps, and ask about the first one:

The same code in two steps (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const prices = new Map([["tea", 3], ["cake", 4]]);const cart = ["tea", "cake"];const linePrices = cart.map((id) => prices.get(id));//    ^?const total = linePrices.reduce((sum, price) => sum + price, 0);console.log(total);

Line 3 is the first step, with its own name, linePrices. The query on line 4 answers const linePrices: (number | undefined)[]: an array where each item is a number or undefined. So the undefined comes from prices.get(id). A Map gives back undefined for an id it doesn't have. The errors are now on line 5, where the sum uses those values. Give a missing price a value with ?? 0:

A missing price counts as 0Pop out in the code editor (opens in a new tab)TypeScript
const prices = new Map([["tea", 3], ["cake", 4]]);const cart = ["tea", "cake"];const linePrices = cart.map((id) => prices.get(id) ?? 0);//    ^?const total = linePrices.reduce((sum, price) => sum + price, 0);//    ^?console.log(total);

Line 3 adds ?? 0, which gives 0 when the left side is undefined (Nullish coalescing and optional chaining). The query on line 4 now answers const linePrices: number[], and the one on line 6 answers const total: number. No errors, and line 7 prints 7.

A starting value can cause errors too. An empty object {} has the type {}: an object with no properties.

Prices by name, from an empty start (an error on purpose)Pop 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 }];const byName = cart.reduce((totals, item) => {  totals[item.name] = item.price;  return totals;}, {});console.log(byName);

Line 3 builds an object with reduce, starting from {} on line 6. Line 4 stores each price under its item's name, and TypeScript marks it: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. Read the end first: the type is {}, which has no room for names. The fix is to name the type you mean and give it to the starting value:

Prices by name, from a typed startPop 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 }];type PriceList = Record<string, number>;const start: PriceList = {};const byName = cart.reduce((totals, item) => {  totals[item.name] = item.price;  return totals;}, start);console.log(byName);

Line 3 names the type PriceList: an object whose keys are strings and whose values are numbers (Utility types covers Record). Line 4 makes the empty start with that type, and line 8 passes it in. reduce now knows what it's building, so there are no errors, and line 9 prints { Tea: 3, Cake: 4 }. Point at byName to see const byName: PriceList.

These moves work on most confusing errors:

Ways to investigate an error. Read each row as: when to use it, what to do, and what it shows you.
WhenTryWhat it shows
You don't know what type a name hasPoint at it, or add a // ^? line under it.The type TypeScript worked out for it.
A long line has an error deep insideSplit it into steps, each with its own name.The first step whose type isn't what you expected.
The error is far from where you think the mistake isWrite the type you meant: a return type, or a variable's type.The error moves to the line that breaks your type.
An empty {} or [] gets the wrong typeGive the starting value a named type.Errors about the real data, not about {}.
The same error appears in many placesLook for what those places share.One cause, like a parameter typed wrong.

A theme from the address bar

A settings page reads the theme from the page's address, like ?theme=dark, with URLSearchParams. Fix it the way you would in a real project: read the last line, fix that, and read again.

Playground: fix the theme one error at a time
A theme read from the page's addressPop out in the code editor (opens in a new tab)TypeScript
type Theme = "light" | "dark"; function setTheme(theme: Theme) {  console.log(`Theme: ${theme}`);} const params = new URLSearchParams("?theme=dark");setTheme(params.get("theme"));
Console outputTheme: dark
What happens
TypeScript1 error: line 8
Step 1 of 3

Argument of type 'string | null' is not assignable to parameter of type 'Theme'. The last line gives one reason: Type 'null' is not assignable to type 'Theme'. get gives back null when the address has no theme.

TypeScript checks the code for real at every step. The address holds theme=dark, so every step prints the same thing. Reset goes back to step 1.

Line 1 says a Theme is "light" or "dark", and lines 3 to 5 set it. Line 7 reads the address. At step 1, line 8 passes params.get("theme") straight in. Its type is string | null, and the error's last line names only null. At step 2, the if on line 9 removes null, and a second error appears on line 10 about string. It was there all along. TypeScript stops at the first reason it finds, so fixing one reason can show the next. Step 3 checks for the two allowed values (Narrowing explains how the if changes the type), and the errors are gone.

Now practise reading the number. Sort each line by the error TypeScript gives it:

Which error is it?
  • const quantity: number = "2";
  • let total = 0; total = "7";
  • Math.round("4.5");
  • parseInt(3);
  • const user = { name: "Asha" }; user.email;
  • [3, 4].total;
  • const tea: { name: string; price: number } = { name: "Tea" };
  • const user: { name: string; email: string } = { name: "Asha" };
Try it yourself
0 of 8 correct

Each line has one error. Put it under the error number TypeScript reports.

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

Common mix-ups

  • "The first line of an error is the important one." No. It's a summary. The last line of the chain usually names the real mismatch.
  • "The red line is where the mistake is." No. It's where TypeScript noticed. Writing the type you meant, like a return type, moves the error closer to the cause.
  • "In 'X is not assignable to Y', X is what the place needs." No. X is what you gave. Y is what the place needs.
  • "Fixing what the last line says fixes the error." Not always. It names the first reason TypeScript found. Another reason, like the string in the theme, can appear once it's fixed.
  • "An error means the code won't run." No. The code still runs with the types removed. The signup form prints 30, and the cart prints Total: $3.
  • "Adding any fixes an error." It hides it. The value is just as wrong when the code runs.

Practice exercises

Each exercise is TypeScript. Press Edit & run on the starter code to try a fix: the errors update as you type, and you can point at a name to see its type. Guess first, then use the hints.

Exercise 1 · Warm-upName the error number

Without running it: which error number will TypeScript report for this code?

Starter codePop out in the code editor (opens in a new tab)TypeScript
function addToCart(name: string, quantity: number) {
  console.log(`${quantity} x ${name}`);
}

addToCart("Tea", "2");

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

    Exercise 2 · Warm-upFind the wrong property in a long error

    Read the error on line 10. Which property has the wrong type? Then fix the code.

    Starter codePop out in the code editor (opens in a new tab)TypeScript
    type Address = { street: string; zip: string };type Customer = { name: string; address: Address };type ApiCustomer = { name: string; address: { street: string; zip: number } }; function shipTo(customer: Customer) {  console.log(`${customer.name}, ${customer.address.zip}`);} const fromServer: ApiCustomer = { name: "Asha", address: { street: "Oak Street 12", zip: 56001 } };shipTo(fromServer);

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

      Exercise 3 · PracticeAdd what the profile is missing

      Which property is the profile missing? Add it so the error goes away.

      Starter codePop out in the code editor (opens in a new tab)TypeScript
      type Profile = { name: string; email: string; newsletter: boolean }; const asha: Profile = {  name: "Asha",  email: "asha@example.com",};console.log(asha.newsletter ? "Subscribed" : "Not subscribed");

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

        Exercise 4 · PracticeMove the error to the typo

        TypeScript marks line 7, but the mistake is somewhere else. Add a return type to toProduct. Which line does TypeScript mark now? Then fix it.

        Starter codePop out in the code editor (opens in a new tab)TypeScript
        type Product = { name: string; price: number }; function toProduct(name: string, cents: number) {  return { name, prise: cents / 100 };} const tea: Product = toProduct("Tea", 300);console.log(tea.price);

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

          Exercise 5 · ChallengeSplit a line to find the undefined

          What does this code print when it runs? Then split line 3 into two steps, find where the undefined comes from, and fix it.

          Starter codePop out in the code editor (opens in a new tab)TypeScript
          const stock = new Map([["tea", 5], ["cake", 2]]);const order = ["tea", "cake", "scone"];const left = order.map((id) => stock.get(id)).reduce((sum, count) => sum + count, 0);console.log(left);

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

            Exercise 6 · ChallengeRead a no-overload error

            A search box should react to the Enter key. Read the error on line 2. What type of event does a click give? Then fix the code.

            Starter codePop out in the code editor (opens in a new tab)TypeScript
            const search = document.createElement("input");search.addEventListener("click", (event: KeyboardEvent) => {  if (event.key === "Enter") console.log("Search");});

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

              Check your understanding

              The quiz shows its code without the checker, so the error list doesn't give the answers away. Read each error the way the lesson does: what you gave, what the place needs, and the last line of the chain.

              The reading type errors quiz · 7 questionsScore: first tries count
              1. Question 1 of 7In Type 'string' is not assignable to type 'number', which type does the place need?

                Choose an answer to see the explanation.

              2. Question 2 of 7Which property in this long error has the wrong type?

                Read the code, then predictText
                Argument of type 'ApiOrder' is not assignable to parameter of type 'Order'.
                  Types of property 'items' are incompatible.
                    Type '{ name: string; quantity: string; }[]' is not assignable to type 'OrderItem[]'.
                      Type '{ name: string; quantity: string; }' is not assignable to type 'OrderItem'.
                        Types of property 'quantity' are incompatible.
                          Type 'string' is not assignable to type 'number'.

                Choose an answer to see the explanation.

              3. Question 3 of 7Which error number does this cart item get?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                type CartItem = { name: string; price: number };
                const tea: CartItem = { name: "Tea", price: 3, size: "large" };

                Choose an answer to see the explanation.

              4. Question 4 of 7Which line does TypeScript mark in this order code?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                type Order = { id: number; total: number };
                
                function makeOrder(id: number, amount: number) {
                  return { id, totl: amount };
                }
                
                const order: Order = makeOrder(7, 12);

                Choose an answer to see the explanation.

              5. Question 5 of 7What does 'cake' is possibly 'undefined' ask you to do?

                Choose an answer to see the explanation.

              6. Question 6 of 7An error starts with No overload matches this call. What should you read first?

                Choose an answer to see the explanation.

              7. Question 7 of 7A long line with map and reduce has an error deep inside. What helps you find where the type went wrong?

                Choose an answer to see the explanation.

              Key takeaways

              • An error has a place, a message, and a number like ts(2322). Search for the number as TS2322.
              • In Type 'X' is not assignable to type 'Y', X is what you gave and Y is what the place needs.
              • A long error is a chain: each line says why about the one above. Start at the last line, and use the lines above as the path.
              • For "No overload matches this call", read the chain for the way of calling you meant.
              • The red line is where TypeScript noticed. Write the type you meant, like a return type, to move it to the mistake.
              • Point at names, add ^? queries, split long lines, and name types to see where a type went wrong.
              • Fixing the last line can reveal the next reason. Read again after each fix.

              Remember the one-liner.
              Read what you gave and what was needed, start a long error from its last line, and move the error to the mistake by writing the type you meant.

              Coming next: Habits of good TypeScript. It collects the habits that keep errors like these rare and easy to read: letting inference work, avoiding any, and modelling states with unions.

              CompleteFrontend Clear concepts. Working examples.