2

I got here:

buyTicketData?.pricingOptions

this error:

[tsl] ERROR in /Applications/MAMP/htdocs/wp-content/plugins/tikex/tikexModule/components/BuyTicket/PricingOptionInvoiceItemsFormFieldsCheckboxes.tsx(280,25)
      TS2532: Object is possibly 'undefined'.

Why it matters if left side of ? is undefined, ? wraps it, not?

here are the types:

buyTicketData?: BuyTicketData;

export type BuyTicketData = {
  pricingOptions?: PricingOptions;
}

export type PricingOptions = {
  [optionId: string]: PricingOptionType;
};

export type PricingOptionType = {
  invoiceItems?: InvoiceItems;
};

export type InvoiceItems = {
  [invoiceItemId: string]: InvoiceItemData;
};

export type InvoiceItemData = {
  defaultValue?: number;
};

This is the whole expression anyway

<select
value={
startPaymentIn?.invoiceItems?.[key] != undefined
  ? startPaymentIn?.invoiceItems?.[key] == 1
    ? "Igen"
    : "Nem"
  : startPaymentIn?.pricingOptionId &&
    buyTicketData?.pricingOptions?.[ // <-- here
      startPaymentIn!.pricingOptionId!
    ].invoiceItems[key]?.defaultValue != undefined
  ? startPaymentIn?.pricingOptionId &&
    buyTicketData?.pricingOptions?.[
      startPaymentIn!.pricingOptionId!
    ].invoiceItems[key]?.defaultValue == 1
    ? "Igen"
    : "Nem"
  : undefined
}

OK, find the solution:

value={
  startPaymentIn?.invoiceItems?.[key] != undefined
    ? startPaymentIn?.invoiceItems?.[key] == 1
      ? "Igen"
      : "Nem"
    : buyTicketData?.pricingOptions?.[
        startPaymentIn?.pricingOptionId ?? ""
      ]?.invoiceItems?.[key]?.defaultValue != undefined
    ? buyTicketData?.pricingOptions?.[
        startPaymentIn?.pricingOptionId ?? ""
      ]?.invoiceItems?.[key]?.defaultValue == 1
      ? "Igen"
      : "Nem"
    : undefined
}

I just do not know why this ugly ?? "" condition need.

Inigo
  • 12,186
  • 5
  • 41
  • 70
János
  • 32,867
  • 38
  • 193
  • 353
  • You could write a custom tag to do this. – Nick Jan 10 '22 at 19:36
  • It would help both you and us if you provided a [mre]. – Inigo Jan 14 '22 at 01:15
  • Ok, I produced a [mre] for you, in [my answer](https://stackoverflow.com/a/70705246/8910547). – Inigo Jan 14 '22 at 02:03
  • Janos, I think this is a bit unfair, because you approved the answer that didn't actually fix the problem *as you stated it*. That's the problem when you don't supply an [mre]. I took your code as-is, and isolated the part that was generating the error in the question title, and provided a fix. The answer you approved solved a different problem: not having to use the `!` operator in your expression (which you didn't mention was an issue. Maybe in the actual code context those were fine). In other words, I wasted time carefully solving you problem as stated and writing out an answer. – Inigo Jan 14 '22 at 02:24

2 Answers2

5

If a is undefined, a.b throws exception while a?.b resolves to undefined. You still need to handle the undefined.

buyTicketData?.pricingOptions?.[startPaymentIn?.pricingOptionId]

resolves to

buyTicketData?.pricingOptions?.[undefined]

if startPaymentIn is undefined. This would throw error as undefined cannot be a key.

A better way is to do a null check before everything if this variable is essential, so that you don't need ?. at all.

if(startPaymentIn)
{
    //no need to use ?. on startPayment
}
Ricky Mo
  • 6,285
  • 1
  • 14
  • 30
0

You missed one optional chaining operator for the possibly undefined invoiceItems. The defaultValue lookup should be like this:

buyTicketData?.pricingOptions?.[startPaymentIn!.pricingOptionId!]
    .invoiceItems?.[key]?.defaultValue

The following minimal reproducible example illustrates this. Try it in Playground to see the errors.

export type BuyTicketData = {
    pricingOptions?: PricingOptions;
}

export type PricingOptions = {
    [optionId: string]: PricingOptionType;
};

export type PricingOptionType = {
    invoiceItems?: InvoiceItems
}

export type InvoiceItems = {
    [invoiceItemId: string]: InvoiceItemData
}

export type InvoiceItemData = {
    defaultValue?: number
}

let startPaymentIn: PricingOptionType & { pricingOptionId?: string } = {}

function testContext (key: string, buyTicketData?: BuyTicketData) {

    // incrementally testing your expression until we isolate the actual error
    let w = buyTicketData?.pricingOptions
    let x = buyTicketData?.pricingOptions?.[startPaymentIn!.pricingOptionId!]
    let y = buyTicketData?.pricingOptions?.[startPaymentIn!.pricingOptionId!].invoiceItems
    let z = buyTicketData?.pricingOptions?.[startPaymentIn!.pricingOptionId!].invoiceItems[key]
    // ^^^ error on this last line
    
    // the correct expression to get the `defaultValue`
    const defaultValue =
        buyTicketData?.pricingOptions?.[startPaymentIn!.pricingOptionId!].invoiceItems?.[key]?.defaultValue

    return startPaymentIn?.invoiceItems?.[key] != undefined
        ? startPaymentIn?.invoiceItems?.[key] == 1
            ? "Igen"
            : "Nem"
        : startPaymentIn?.pricingOptionId &&
          buyTicketData?.pricingOptions?.[
              startPaymentIn!.pricingOptionId!
              ].invoiceItems?.[key]?.defaultValue != undefined
            ? startPaymentIn?.pricingOptionId &&
              buyTicketData?.pricingOptions?.[
                  startPaymentIn!.pricingOptionId!
                  ].invoiceItems?.[key]?.defaultValue == 1
                ? "Igen"
                : "Nem"
            : undefined
}
Inigo
  • 12,186
  • 5
  • 41
  • 70