cf.completefrontend
Open lab My progress
THE TYPESCRIPT FIELD GUIDE

Object types

Describe the shape of an object in TypeScript: required, optional, and read-only properties, and objects inside objects, with products and orders to edit.

By the end, you can
  • 01
    Write an object typeDescribe the properties an object must have and the type of each, and read the errors when one is missing or wrong.
  • 02
    Mark properties optional or read-onlyUse ? for a property that can be left out and readonly for one your code must not change, and know what each one checks.
  • 03
    Type nested objectsDescribe objects inside objects, read nested values safely, and know that readonly covers only one level.

Say what an object must hold

A shop page shows a label for each product, like Tea: $3. A small function builds it from a product object with a name and a price. Here it is in plain JavaScript, called once with a whole product and once with a product that has no price:

A product label in plain JavaScriptPop out in the code editor (opens in a new tab)JavaScript
function productLabel(product) {
  return `${product.name}: $${product.price}`;
}
console.log(productLabel({ name: "Tea", price: 3 }));
console.log(productLabel({ name: "Cake" }));

Line 1 makes productLabel, which takes one product. Line 2 builds the label from its name and price with a template literal. Line 4 prints Tea: $3. Line 5 passes a cake with no price, and prints Cake: $undefined. Reading a property an object doesn't have gives undefined (the Object basics lesson covers this), and nothing warns you.

In TypeScript you can say which properties the product must have, and what type each one is. That description is called an object type. Here is the same code with one added:

The same label with an object type (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
function productLabel(product: { name: string; price: number }) {  return `${product.name}: $${product.price}`;}console.log(productLabel({ name: "Tea", price: 3 }));console.log(productLabel({ name: "Cake" }));

The only change is on line 1: product: { name: string; price: number }. Read it as "product is an object with a name that is a string and a price that is a number". Line 4 passes such an object, so it's fine. Line 5 passes a cake with no price, and TypeScript marks it on purpose, because it's the bug. The message has two lines:

  • Argument of type '{ name: string; }' is not assignable to parameter of type '{ name: string; price: number; }' means "the object you passed doesn't fit what the function asks for". An argument is a value you pass in a call. A parameter is the name that receives it, here product.
  • Property 'price' is missing in type '{ name: string; }' says why: the object has no price, and the type needs one.

Notice how TypeScript writes the type of what you passed: { name: string; }. It describes every object the same way, as a list of property names and their types. Try it: type a different object for line 4, and watch the list under the code.

Playground: pass a product to productLabel
A label for one productPop out in the code editor (opens in a new tab)TypeScript
function productLabel(product: { name: string; price: number }) {  return `${product.name}: $${product.price}`;}console.log(productLabel({ name: "Cake" }));
Line 4 passes{ name: "Cake" }
What happens
TypeScript1 error: line 4
When it runsprints Cake: $undefined
Try it yourself

The object has a name but no price. TypeScript marks line 4: Property 'price' is missing in type '{ name: string; }'. When it runs, product.price is undefined, so the label reads Cake: $undefined.

The code is checked by the real TypeScript compiler each time you type. Only line 4 changes. Reset puts { name: "Cake" } back.

With { name: "Cake", price: 4 }, every property is there with the right type, and the error is gone. The order of the properties doesn't matter. A price in quotes is text, so it gets Type 'string' is not assignable to type 'number'. An empty {} is missing both properties, and leaving the box empty passes no object at all. An extra property, like colour: "green", gets an error too: Object literal may only specify known properties. The Excess property checks lesson explains when TypeScript checks for extras.

Left, a window titled type lists name: string and price: number. An arrow labelled checks points at a cart called cake that holds only one card, name: "Cake". A note above the cart says price is missing.typename: stringprice: numberwhat line 1 asks forchecksprice is missingname: "Cake"cake
The type on line 1 is a list: a name that is text and a price that is a number. TypeScript checks the cake from line 5 against that list and finds no price.
Real-life analogyA delivery form

A delivery form has a box for your name, a box for your phone number, and a box for your address. A box marked "optional", like "Apartment number", can stay empty. The order number is printed at the top, and you can't write over it. Before the clerk takes your form, they check that every box that must be filled is filled with the right kind of thing.

In real life: The form lists the boxes to fill in
In TypeScript: An object type lists the properties
In real life: Each box says what goes in it: a name, a phone number
In TypeScript: Each property has a type: price: number
In real life: A box marked "optional" can stay empty
In TypeScript: nickname?: string can be left out
In real life: The order number is printed, and you can't write over it
In TypeScript: readonly id: number can't be changed
In real life: The clerk checks the form before taking it
In TypeScript: TypeScript checks the object before the code runs
The main idea

An object type describes the shape of an object: which properties it has and the type of each one, like { name: string; price: number }. TypeScript checks every object you give it against that shape: a missing property, a property with the wrong type, or reading a property the type doesn't list gets an error.

Writing an object type

You can write an object type anywhere a type goes. After a function parameter, as in the overview, is the most common place. After a variable name works the same way, and the type stays with the variable:

A product variable with an object type (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
let product: { name: string; price: number } = { name: "Tea", price: 3 };product = { name: "Cake", price: 4 };product.price = "5";console.log(product.price);

Line 1 says product must always hold an object with a string name and a number price, and gives it the tea. Line 2 puts a different object in it, a cake, which has the same shape, so it's fine. Line 3 changes just the price to the text "5". TypeScript marks it on purpose: Type 'string' is not assignable to type 'number', "you're putting text where a number has to go". Run it anyway, and line 4 prints 5: the text, which would break any sum later.

A few rules about how you write the type itself:

  • Each property is a name, a colon, and a type: price: number.
  • Properties are separated by semicolons, commas, or new lines. { name: string, price: number } means the same.
  • The order of the properties doesn't matter, in the type or in the object.
  • A long type can spread over several lines, one property per line.
A type over several lines, and properties in another orderPop out in the code editor (opens in a new tab)TypeScript
function shippingLabel(order: {  id: number;  city: string;}) {  return `Order ${order.id} to ${order.city}`;}console.log(shippingLabel({ city: "Pune", id: 7 }));

Lines 1 to 4 are the parameter order and its type: an id that is a number on line 2, and a city that is a string on line 3. Line 5 builds the label. Line 7 passes the city first and the id second, and there's no error. It prints Order 7 to Pune.

You don't always write the type. When a variable starts with an object, TypeScript works out its type from the object. This is inference, from the Type annotations & inference lesson:

TypeScript works out an object's type (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const product = { name: "Tea", price: 3, inStock: true };//    ^?console.log(product.colour);

Line 1 makes a product with three properties and no type written. The // ^? comment on line 2 asks TypeScript for the type of the name its ^ points at, and the page writes the answer after it: an object type with name: string, price: number, and inStock: boolean (a boolean is true or false). Line 3 asks for product.colour, which isn't in that type. TypeScript marks it on purpose: Property 'colour' does not exist on type …. In plain JavaScript it would print undefined.

So TypeScript knows an object's shape whether you write it or not. You write object types where there's no value to work them out from, which is mostly function parameters: a function can't know what callers will pass.

Properties that can be left out

Some properties are often missing. A user profile always has a name, but not every user picks a nickname. Put a question mark after the name of a property, nickname?: string, and the property becomes optional: an object may leave it out. If it's there, it must be a string.

Reading an optional nicknamePop out in the code editor (opens in a new tab)TypeScript
const user: { name: string; nickname?: string } = { name: "Asha" };const nickname = user.nickname;//    ^?console.log(nickname);

Line 1 makes Asha's profile with only a name, which is fine because nickname is optional. Line 2 reads the nickname. The query on line 3 shows its type: string | undefined. The | means "or": the nickname is a string or undefined, because the property may not be there. Line 4 prints undefined. (The Union types lesson covers | in full.)

Left, a cart called asha holds one card, name: "Asha", and reading user.nickname gives undefined. Right, a cart called ben holds name: "Ben" and nickname: "Benji", and reading user.nickname gives "Benji".Asha has no nicknamename: "Asha"ashauser.nickname → undefinedBen has onename: "Ben"nickname: "Benji"benuser.nickname → "Benji"
Asha's object has no nickname, so reading it gives undefined. Ben's has one. The type { name: string; nickname?: string } fits both, so TypeScript says reading the nickname gives string | undefined.

Because the nickname may be undefined, TypeScript won't let you use it as a string until you've handled that case. Try four ways to turn a user into a display name. Asha has no nickname; Ben's is Benji:

Playground: use a nickname that may be missing
A display name from an optional nicknamePop out in the code editor (opens in a new tab)TypeScript
function displayName(user: { name: string; nickname?: string }) {  return user.nickname.toUpperCase();}console.log(displayName({ name: "Asha" }));console.log(displayName({ name: "Ben", nickname: "Benji" }));
TypeScript1 error: line 2
What it prints for each call
AshaTypeError: Cannot read properties of undefined (reading 'toUpperCase')
Try it yourself

Line 2 calls toUpperCase() on the nickname without checking it. TypeScript marks it: 'user.nickname' is possibly 'undefined'. It's right: Asha has no nickname, so the first call throws a TypeError and the code stops.

TypeScript checks the code for real, and the console shows what this code prints. Each button changes only line 2. Reset goes back to Use it directly.

Use it directly gets 'user.nickname' is possibly 'undefined', which means "this might be undefined, and you can't call a method on undefined". Run it, and Asha's call throws a TypeError. The other three handle the missing nickname, so the error goes away: Check it first with ? :, Fall back with ?? to the name, or use optional chaining ?., which gives undefined instead of throwing. The Nullish coalescing and optional chaining lesson explains ?? and ?..

A question mark isn't the same as writing | undefined in the type yourself. Compare three profiles:

Optional, or allowed to be undefined (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const asha: { name: string; nickname?: string } = { name: "Asha" };const ben: { name: string; nickname: string | undefined } = { name: "Ben" };const chen: { name: string; nickname: string | undefined } = { name: "Chen", nickname: undefined };

Line 1 uses nickname?, so Asha can leave it out. Line 2 says nickname: string | undefined with no question mark. The value may be undefined, but the property must be written, so TypeScript marks line 2 on purpose: Property 'nickname' is missing in type '{ name: string; }'. Line 3 writes nickname: undefined, and that's fine.

The table below compares the two. Read each row as a question, then the answer for each way of writing the type.

An optional property, or one that allows undefined
Questionnickname?: stringnickname: string | undefined
Can the object leave nickname out?Yes. { name: "Asha" } is fine.No. Every object must write it, even as nickname: undefined.
What type does reading it give?string | undefined.string | undefined.
When is it the better choice?When the property is often simply not there, like a nickname.When every object must say something about it, even "no value".

Read-only properties

Some properties should never change once an object exists, like an order's id. Write readonly before the property, and TypeScript reports any line that assigns to it:

An order id that must not change (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const order: { readonly id: number; total: number } = { id: 7, total: 10 };order.total = 12;order.id = 8;console.log(order.id, order.total);

Line 1 says the order has a read-only id and a total you can change, and makes order 7 with a total of 10. Line 2 changes the total to 12, which is fine. Line 3 tries to change the id, and TypeScript marks it on purpose: Cannot assign to 'id' because it is a read-only property. "Assign" means "store a new value with =".

Now run it. Line 4 prints 8 12: the id really changed. readonly is a TypeScript check, like every type. It's removed with the other types before the code runs, so nothing stops the change in the browser.

Left, an editor window shows order.id = 8 with the note id is read-only: TypeScript marks line 3. An arrow labelled types removed leads to a browser window, where the order's id is now 8: the change still happens.As you writeeditororder.id = 8;id is read-onlyTypeScript marks line 3typesremovedWhen it runsbrowserid: 8the order nowthe change still happens
In the editor, TypeScript marks order.id = 8 because id is read-only. The types are removed before the code runs, so the browser still changes the id to 8.

That's still useful. It catches the mistake while you write, which is when you want to hear about it. If you also need the object locked while the code runs, JavaScript has Object.freeze (the Immutability lesson covers it).

You've now seen three ways to write a property. The table below compares them. Read each row as one way of writing a property, then what it allows.

Three ways to write a property
In the typeCan an object leave it out?Can your code change it?What does reading it give?
price: numberNo. TypeScript reports the missing property.Yes.A number.
price?: numberYes.Yes.A number or undefined, so check it before you use it.
readonly price: numberNo.No. TypeScript reports Cannot assign to 'price'.A number.

Objects inside objects

A property can hold another object. An order has a shipping address, and the address has a city and a zip code. The type of that property is an object type too, written inside the outer one:

An order with an address insidePop out in the code editor (opens in a new tab)TypeScript
const order: {  id: number;  shipTo: { city: string; zip: string };} = {  id: 7,  shipTo: { city: "Pune", zip: "411001" },};const shipTo = order.shipTo;//    ^?console.log(order.shipTo.city);

Lines 1 to 4 hold the type. Line 2 says the order has a number id. Line 3 says it has a shipTo, and that shipTo is itself an object with a city and a zip, both strings. Lines 4 to 7 make the order, with the inner object on line 6. Line 8 reads order.shipTo, and the query on line 9 shows its type: the inner object type from line 3. Line 10 reads two levels deep and prints Pune.

A cart called order holds a card id: 7 and a card shipTo. An arrow leads from shipTo to a second cart, called shipTo, which holds city: "Pune" and zip: "411001". Below, order.shipTo.city gives "Pune".id: 7shipToordercity: "Pune"zip: "411001"shipToorder.shipTo.city → "Pune"
order holds an id and another object, shipTo. Reading order.shipTo.city goes into order, then into shipTo, and gives "Pune". Line 3 of the code describes the inner object.

TypeScript checks every level. Change what line 6 puts in shipTo, and watch where the error lands:

Playground: fill in the shipping address
An order with a shipping addressPop out in the code editor (opens in a new tab)TypeScript
const order: {  id: number;  shipTo: { city: string; zip: string };} = {  id: 7,  shipTo: { city: "Pune", zip: "411001" },};console.log(`Ship to ${order.shipTo.city}, ${order.shipTo.zip}`);
Shipping labelShip to Pune, 411001
What happens
TypeScriptNo errors
Try it yourself

Line 6 gives shipTo an object with a city and a zip, both text. It matches the inner type on line 3, so there are no errors, and the label reads Ship to Pune, 411001.

TypeScript checks the code for real, and the label is what this code prints. Each button changes only line 6. Reset goes back to Full address.

The error lands on line 6, inside the order, at the exact property that's wrong. A zip as a number is the sneaky one: the label looks right, so plain JavaScript would never tell you. A whole address written as one string gets an error that quotes the inner type.

readonly works one level at a time. A read-only property that holds an object stops you from replacing the object, but not from changing what's inside it:

A read-only address can still change inside (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
const order: {  readonly id: number;  readonly shipTo: { city: string };} = { id: 7, shipTo: { city: "Pune" } }; order.shipTo.city = "Goa";order.shipTo = { city: "Delhi" };console.log(order.shipTo.city);

Lines 1 to 4 make an order whose shipTo is read-only. Line 6 changes the city inside it to Goa, and TypeScript allows it: city itself isn't read-only. Line 7 replaces the whole address, and TypeScript marks it on purpose: Cannot assign to 'shipTo' because it is a read-only property. Run it anyway, and line 8 prints Delhi, because line 7 still runs. To lock the city too, write readonly on city as well.

An inner object can be optional too. Then you have to check that it's there before you read inside it:

Reading inside an address that may be missing (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
function shippingCity(order: { id: number; shipTo?: { city: string } }) {  return order.shipTo.city;}console.log(shippingCity({ id: 7 }));

Line 1 says shipTo is optional, with the question mark. Line 2 reads order.shipTo.city without checking. TypeScript marks it on purpose: 'order.shipTo' is possibly 'undefined'. Line 4 passes an order with no address, and when it runs, reading city of undefined throws a TypeError. Here is the fix:

Reading an optional address safelyPop out in the code editor (opens in a new tab)TypeScript
function shippingCity(order: { id: number; shipTo?: { city: string } }) {  return order.shipTo?.city ?? "No address yet";}console.log(shippingCity({ id: 7 }));console.log(shippingCity({ id: 8, shipTo: { city: "Pune" } }));

Line 2 uses ?., which stops and gives undefined when shipTo is missing, and ??, which then gives "No address yet" instead. Line 4 prints No address yet. Line 5 passes an order with an address and prints Pune.

A profile card on an account page

An account page shows a card for the signed-in user. The user object comes with an id that must never change, a name, a picture the user may not have uploaded, and an address. One parameter type describes all of it:

A profile card that uses all four ideasPop out in the code editor (opens in a new tab)TypeScript
function profileCard(user: {  readonly id: number;  name: string;  avatarUrl?: string;  address: { city: string; country: string };}) {  const avatar = user.avatarUrl ?? "default-avatar.png";  return `${user.name} from ${user.address.city} (${avatar})`;} console.log(profileCard({  id: 1,  name: "Asha",  address: { city: "Pune", country: "India" },}));

Lines 1 to 6 are the function and its parameter's type:

  • Line 2: readonly id, because a user's id never changes.
  • Line 3: a name that every user has.
  • Line 4: avatarUrl?, a picture address that may be missing.
  • Line 5: an address object inside the user, with a city and a country.

Line 7 falls back to a default picture with ??, because avatarUrl may be undefined. Line 8 reads the city two levels deep. Lines 11 to 15 call the function with Asha, who has no picture, and print Asha from Pune (default-avatar.png). Press Edit & run and try removing the address, or reading user.avatarUrl.length: each gets an error from this lesson.

Error or fine?
  • const tea: { name: string; price: number } = { name: "Tea", price: 3 };
  • const tea: { name: string; price: number } = { name: "Tea" };
  • const tea: { name: string; price: number } = { price: 3, name: "Tea" };
  • const user: { name: string; nickname?: string } = { name: "Asha" };
  • const user: { name: string; nickname?: string } = { name: "Asha" }; user.nickname.length;
  • const order: { readonly id: number } = { id: 7 }; order.id = 8;
  • const order: { readonly id: number } = { id: 7 }; console.log(order.id + 1);
  • const order: { shipTo: { city: string } } = { shipTo: { city: 411001 } };
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

One mix-up comes from JavaScript itself. When a function takes an object, you often unpack its properties right in the brackets, which is called destructuring. It looks natural to add the types there:

Types written inside destructuring (an error on purpose)Pop out in the code editor (opens in a new tab)TypeScript
function productLabel({ name: string, price: number }) {  return `${string}: $${number}`;}console.log(productLabel({ name: "Tea", price: 3 }));

In destructuring, name: string already means something in JavaScript: "take the property name and store it in a variable called string". So line 1 makes two variables named string and number, and line 2 uses them. TypeScript marks line 1 twice on purpose: Binding element 'string' implicitly has an 'any' type, which means "nothing says what type this variable is" (any is the next lesson's topic). It still prints Tea: $3. The fix puts the object type after the whole pattern:

The object type after the destructuring patternPop out in the code editor (opens in a new tab)TypeScript
function productLabel({ name, price }: { name: string; price: number }) {  return `${name}: $${price}`;}console.log(productLabel({ name: "Tea", price: 3 }));

Line 1 unpacks name and price, then gives the whole object its type after the closing brace. No errors, and line 4 prints Tea: $3.

Another mix-up: const doesn't make an object's properties read-only.

A const object can still changePop out in the code editor (opens in a new tab)TypeScript
const cart = { total: 3 };cart.total = 5;console.log(cart.total);

Line 1 makes a const cart. Line 2 changes its total, and TypeScript reports nothing. Line 3 prints 5. const means the name cart always points at this object; the object itself can change (the Objects and references lesson explains why).

  • "The properties must be in the same order as the type." No. Order never matters, only names and types.
  • "nickname?: string is the same as nickname: string | undefined." No. With ?, the property can be left out. With | undefined, it must be written, even as undefined.
  • "readonly stops the change while the code runs." No. It's removed with the other types. The order example still printed 8 12. Use Object.freeze for that.
  • "A read-only object can't change anywhere inside." No. readonly covers one property. The city inside a read-only shipTo still changed to Goa.
  • "const makes the properties read-only." No. It only stops the name from pointing at a different object.
  • "I have to write a type for every object." No. TypeScript works out the type of an object you store in a variable. Write object types mostly for function parameters.

The table below compares three ways to stop changes. Read each row as one thing you can write, then what it stops, and when.

const, readonly, and Object.freeze
What you writeWhat it stopsWhen is it checked?
const cart = { total: 3 }Giving the name cart a different object. Its properties can still change.Both. TypeScript reports it as you write, and JavaScript throws a TypeError when it runs.
readonly total: numberWriting cart.total = 5 in your code.Only as you write. The types are removed before the code runs, so the change still happens.
const cart = Object.freeze({ total: 3 })Any change to the properties of cart, but not to objects inside it.Both. Object.freeze gives back a read-only type, so TypeScript reports a change as you write. When the code runs, the change doesn't happen: in a module, which runs in strict mode, it throws a TypeError.

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 missing property

TypeScript reports one error for these page settings. Which property is missing?

Starter codePop out in the code editor (opens in a new tab)TypeScript
const settings: { theme: string; fontSize: number; showTips: boolean } = {
  theme: "dark",
  fontSize: 16,
};

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

    Exercise 2 · Warm-upRead an optional property's type

    What type does TypeScript give size? Guess first. Then point at size 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 settings: { theme: string; fontSize?: number } = { theme: "dark" };const size = settings.fontSize;

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

      Exercise 3 · PracticeAdd a property to a todo's type

      A todo list labels each todo with a box. Fix the type on line 1 so line 2 has no error. What does the fixed code print?

      Starter codePop out in the code editor (opens in a new tab)TypeScript
      function todoLabel(todo: { title: string }) {  return (todo.done ? "[x] " : "[ ] ") + todo.title;} const todo = { title: "Buy tea", done: true };console.log(todoLabel(todo));

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

        Exercise 4 · PracticeMake a setting optional, with a default

        Some settings come without a font size. Change the type so line 4 is allowed, and return 16 when the size is missing. What does the fixed code print?

        Starter codePop out in the code editor (opens in a new tab)TypeScript
        function fontSizeOf(settings: { theme: string; fontSize: number }) {  return settings.fontSize;}console.log(fontSizeOf({ theme: "dark" }));

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

          Exercise 5 · ChallengeRead-only, one level deep

          TypeScript reports no errors here, even though shipTo is read-only. What does the code print? Then change the type so TypeScript marks line 6.

          Starter codePop out in the code editor (opens in a new tab)TypeScript
          const order: {  readonly id: number;  readonly shipTo: { city: string };} = { id: 7, shipTo: { city: "Pune" } }; order.shipTo.city = "Goa";console.log(order.shipTo.city);

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

            Exercise 6 · ChallengeType nested alert settings

            A settings page keeps its alert choices in an object inside the settings. Write the inner type so line 2 has no error. What does the fixed code print?

            Starter codePop out in the code editor (opens in a new tab)TypeScript
            function describeSettings(settings: { theme: string }) {  const sound = settings.alerts.sound ? "on" : "off";  return `${settings.theme} theme, sound ${sound}`;} const settings = { theme: "dark", alerts: { sound: false, email: true } };console.log(describeSettings(settings));

            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 Object types quiz · 7 questionsScore: first tries count
              1. Question 1 of 7What does { name: string; price: number } say about an object?

                Choose an answer to see the explanation.

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

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                function cartLine(item: { name: string; price: number; quantity: number }) {
                  return item.price * item.quantity;
                }
                console.log(cartLine({ name: "Tea", price: 3, quantity: 2 }));
                console.log(cartLine({ name: "Cake", price: 4 }));

                Choose an answer to see the explanation.

              3. Question 3 of 7What type does TypeScript give size on line 2?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const settings: { theme: string; fontSize?: number } = { theme: "dark" };
                const size = settings.fontSize;

                Choose an answer to see the explanation.

              4. Question 4 of 7TypeScript marks line 2 of this order. What does the code print when it runs anyway?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const order: { readonly id: number } = { id: 7 };
                order.id = 8;
                console.log(order.id);

                Choose an answer to see the explanation.

              5. Question 5 of 7Does TypeScript allow changing a property of a const object, and what prints?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const settings = { theme: "dark" };
                settings.theme = "light";
                console.log(settings.theme);

                Choose an answer to see the explanation.

              6. Question 6 of 7Which of these two lines does TypeScript reject?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const asha: { name: string; nickname?: string } = { name: "Asha" };
                const ben: { name: string; nickname: string | undefined } = { name: "Ben" };

                Choose an answer to see the explanation.

              7. Question 7 of 7Is line 2 allowed, when shipTo is read-only?

                Read the code, then predictPop out in the code editor (opens in a new tab)TypeScript
                const order: { readonly shipTo: { city: string } } = { shipTo: { city: "Pune" } };
                order.shipTo.city = "Goa";
                console.log(order.shipTo.city);

                Choose an answer to see the explanation.

              Key takeaways

              • An object type lists an object's properties and the type of each: { name: string; price: number }.
              • TypeScript reports a missing property, a property with the wrong type, and reading a property the type doesn't have.
              • Order doesn't matter. Separate properties with semicolons, commas, or new lines.
              • nickname?: string can be left out, and reading it gives string | undefined, so handle the missing case with a check, ??, or ?..
              • readonly id: number makes TypeScript report any change to id. It covers one level, and it's gone when the code runs.
              • A property's type can be another object type, and TypeScript checks every level.

              Remember the one-liner.
              An object type is a checklist of property names and types; ? makes a line optional and readonly makes it read-only.

              Coming next: any, unknown & never. It covers the type that turns checking off, the safe type for values you don't know yet, and the type that has no values at all.

              CompleteFrontend Clear concepts. Working examples.