-1

I have this Try it Yourself TypeScript Optional Chaining example from W3Schools TypeScript Null & Undefined section in screenshot below.

TS Optional Chaining No Data

I can see that the purpose of the example is to show you that when data is undefined, it displays No Yard, but it is unclear to me why this is happening and how you can make it display Yard size is 500 sqft ?

My understanding is that this code below is using a new type (House interface), defining a variable called home and has sqft property with a value of 500.

let home: House = {   sqft: 500 }

Code below is using an interface called House, that specifies property names along with it's types. It specifies sqft property as a number type and then it says yard? is an optional property and has a sqft property within it of number type.

interface House {
  sqft: number;
  yard?: {
    sqft: number;
  };
}

Now with the code below, this is where I am not sure why yard size is undefined and showing No yard.

function printYardSize(house: House) {
  const yardSize = house.yard?.sqft;

  if (yardSize === undefined) {
    console.log('No yard');
  } else {
    console.log(`Yard is ${yardSize} sqft`);
  }
}

My understanding is that the function is picking up properties and their types from House interface, using a variable const yardSize to pick up optional yard sqft. Finally it is using an if else statement to display the result

If someone can give me a good understanding on how it works both ways with an undefined No yard and and a value shown with Yard is 500 sqft, then that will be appreciated help, thanks ?

  • "Now with the code below, this is where I am not sure why yard size is undefined and showing" — Well. You haven't shown us the value you are passing to the `house` argument so we can't tell why it is undefined or why you might expect it to be other wise. – Quentin Feb 02 '23 at 11:42
  • "If someone can give me a good understanding on how it works both ways" — This is just a combination of some *super*-basic bits of JS (`if`, object properties, function calls, and variables) and the optional chaining operator which is what the tutorial you are reading is trying to teach you. It's really unclear what you don't understand. – Quentin Feb 02 '23 at 11:45
  • 1
    Are you confusing the house size and the yard size? – Quentin Feb 02 '23 at 11:46
  • Consoles are in JavaScript function, I get that because there are 2 conditions. I didn't mention before that it has printYardSize(home) // prints no yard , at bottom of code. I just want to make this clear, I have 2 questions. Why is it undefined and shows no yard ? and how do you get it to show Yard size is 500 sqft ? – Rob Wilkinson Feb 02 '23 at 12:00
  • There is a value of 500 sqft in, let home: House = { sqft: 500 } , so there is a value that can be obtained, it is just a matter of how ? – Rob Wilkinson Feb 02 '23 at 12:03
  • Umm. `house.sqft` You **are** confusing the house size and the yard size. The house size is 500sq ft. It doesn't have a yard at all. The code is designed to show the yard size. – Quentin Feb 02 '23 at 13:03

2 Answers2

0

It appears as though you might be confusing the two sqft properties:

The one at the top level is associated to the House itself:

interface House {
  sqft: number; // This one
  yard?: {
    sqft: number;
  };
}

and can be accessed this way on a value of type House:

house.sqft
    //^? (property) House.sqft: number

You can see that the type is number. It must be defined for any value of type House.

Additionally, the house might have a yard property or might not — in which case it will be undefined.

See optional properties in the TS handbook for more info.

Example:

house.yard
    //^? (property) House.yard?: { sqft: number } | undefined

If the yard property is not undefined, then it must be an object with its own sqft property that must be a number:

interface House {
  sqft: number;
  yard?: {
    sqft: number; // This one
  };
}

Trying to access that nested property without using the optional chaining operator (?.) will result in a compile-time type error:

house.yard.sqft /* Error
~~~~~~~~~~
'house.yard' is possibly 'undefined'.(18048) */

But using that operator allows for accessing the nested value (if the yard object exists), or evaluating to undefined (if the yard object doesn't exist):

house.yard?.sqft
          //^? (property) sqft: number | undefined

This evaluated value can be stored in another variable, just like in the function that you showed:

const yardSize = house.yard?.sqft;
    //^? const yardSize: number | undefined

TS Playground


Now, to address your questions:

Why is it undefined and shows no yard?

let home: House = {
  sqft: 500, // sqft of home
};

printYardSize(home); // "No yard"

In the code above, the home has no yard property with a nested sqft property, so — in the function — the yardSize variable is undefined. This causes the first conditional branch to execute:

const yardSize = house.yard?.sqft;

if (yardSize === undefined) {
  console.log("No yard");
}

How do you get it to show Yard size is 500 sqft?

let home2: House = {
  sqft: 500,
  yard: {
    sqft: 500, // sqft of yard
  },
};

printYardSize(home2); // "Yard is 500 sqft"

As shown above, you can set the yard property to an object with a sqft property value of 500. This causes the else branch to execute instead:

else {
  console.log(`Yard is ${yardSize} sqft`);
}

You could alternatively set the yard property on the first home after initializing it like this:

home.yard = { sqft: 500 };
printYardSize(home); // "Yard is 500 sqft"

TS Playground

jsejcksn
  • 27,667
  • 4
  • 38
  • 62
  • Aside: the instruction quality of the [TypeScript handbook](https://www.typescriptlang.org/docs/handbook/intro.html) is _much_ better than W3Schools – jsejcksn Feb 02 '23 at 12:59
  • Thanks very much for your help @jcejcksn. I got this understood now and working with No house and Yard. I have my answer below. I was confusing house with the yard at the start. I guess as I am from New Zealand we more think of a yard as a garden. – Rob Wilkinson Feb 13 '23 at 09:54
  • Just one last question I have on this. I wonder why this has a lower case house for accessing a property and in function printYardSize(house: House) ? There is a let home: House and the interface is named with a capital House. – Rob Wilkinson Feb 17 '23 at 11:00
  • [^](https://stackoverflow.com/questions/75322578/how-do-you-get-data-showing-with-typescript-optional-chaining/75323501?noredirect=1#comment133180655_75323501) @RobWilkinson The link to the TypeScript handbook in my previous [comment](https://stackoverflow.com/questions/75322578/how-do-you-get-data-showing-with-typescript-optional-chaining/75323501?noredirect=1#comment132910977_75323501) is the first resource you should consult with any TypeScript questions (even before Stack Overflow). Read through it and you'll probably feel quite confident about the answer to that question and many others. – jsejcksn Feb 17 '23 at 15:25
  • I think you have misunderstood my question for yardSize. There is a let home : house and a function caller with printYardSize(home). There is function printYardSize(house: House) and property is accessed with const yardSize = house.yard?.sqft; My question is how is this possible with house to access home ? I don't think I will be able to find this out through Typescript Handbook in a hurry, as it seems like it one of those unusual things. – Rob Wilkinson Feb 18 '23 at 10:48
  • I also tried let home : House and with function caller printYardSize(home). I put function printYardSize(home: House) and accessed property with const yardSize = home.yard?.sqft; , which I think is the more logical way to do it and it worked OK. So I just would like to clarify how it can work using house instead of home for accessing a property ? – Rob Wilkinson Feb 18 '23 at 10:52
  • [^](https://stackoverflow.com/questions/75322578/how-do-you-get-data-showing-with-typescript-optional-chaining/75323501?noredirect=1#comment133196315_75323501) @RobWilkinson If you have a new question, then you can [ask](https://stackoverflow.com/questions/ask) it, but first be sure to read [ask]. – jsejcksn Feb 18 '23 at 13:36
0

I had a look at this question from 2 perspectives

  1. Using Optional Chaining for optionally finding yard size
  2. or optionally finding house and yard size.

Here is code for Optionally finding yard size

interface House {
  sqft: number;
  yard?: {
    sqft: number;
  };
}
            
function printYardSize(house: House) {
  const yardSize = house.yard?.sqft;

  if (yardSize === undefined) {
    console.log('No yard');
  } else {
    console.log(`Yard is ${yardSize} sqft`);
  }
}
            
let home: House = {
  sqft: 7350,
  yard: {             // Can comment yard property to display No Yard 
         sqft: 2300
        }
};

// Can also set yard property on home after initialising it with
home.yard = { sqft: 2300 }
  

printYardSize(home); // Either prints No yard or Yard is 2300 sqft

When you do not include yard size, it says No Yard and if you include yard size it displays Yard size is 2300 sqft. This means that in home variable declaration, if a property and value are not supplied (null and undefined data) for yard, it does not come back with an undefined error. Instead ? operator allows this data to be optional, there is no error and it display No Yard.

Here is code for Optionally finding house and yard size

// This example with a house and yard size displayed 
interface House {
  sqft?: number,
  yard?: {
          sqft: number;
         };  
}

function printHouseSize(house:House)  {
  // Gets sqft property from let home: House = { sqft:
  const houseSize = house?.sqft;    

  if(houseSize === undefined)  {

    // Displays No House
    console.log('No House');

  } else {
    // Displays House Size
    console.log(`House is ${houseSize} sqft`)
  }
}

function printYardSize(house:House)  {
  // gets sqft property from let home: House = { yard: { sqft:
  const yardSize = house.yard?.sqft;  

  if(yardSize === undefined)  {

    // Displays No Yard
    console.log('No Yard');

  } else {
    // Displays Yard Size
    console.log(`Yard is ${yardSize} sqft`)
  }
} 

/* Declaring a home variable that goes to House interface for getting 
   values types.
   A function later gets property values from here for house and yard. 
   */
let home: House = {
  sqft: 7350,   // Can comment house property to display No House         
  yard: {       // Can comment yard property to display No Yard 
         sqft: 2300    
        }
};

// // Can also set properties on home and yard after initialising 
/* home = {sqft: 7350};
   home.yard = { sqft: 2300 }; */


printHouseSize(home);  // Either prints No House or House is 7350 sqft

printYardSize(home);   // Either prints No yard or Yard is 2300 sqft

When you do not include house size, it says No House and if you include house size it displays House size is 7350 sqft and likewise for yard. This means that if a property and value are not supplied (null and undefined data) for both house and yard, it does not come back with an undefined error. Instead ? operator allows this data to be optional, there is no error and it can display both No House and No Yard.

It is also important to note that ? optional chaining operator is used in interface where property types have been declared and in functions where we get property value, for example const yardSize = house.yard?.sqft; .

Please note: It is not needed in declared home variable because that is where values are set and not where properties are accessed.