Search code examples
typescriptobject-literal

'return object[value1][value2] || default' fails if value1 is not a valid property


I have an object literal with a method to return a sub-property given a particular input, or return a default property if the lookup fails.

//private class, no export
class TemplateSelection {
  'bills';
  'legislators';
}

export class ComponentTemplates {
  private readonly 'notFound';
  private readonly 'data': {
    'us': TemplateSelection,
    'ny': TemplateSelection,
  }

  constructor(){
    this.notFound = PageNotFoundComponent;

    this.data = {
      us: { bills: BillDataComponent, legislators: UsComponent },
      ny: { bills: BillDataComponent, legislators: NyComponent },
    }
  }

  public getData = (requested: RouteParameters) => {
    // TODO: lookup fails if !requested.region, but not if !requested.resourceType?
    return this.data[requested.region][requested.resourceType] || this.notFound;
  }
}
  1. If [requested.region] == 'us' & [requested.resourceType] == 'bills', I get the BillDataComponent component, as expected.
  2. If [requested.region] == 'ny' and [requested.resourceType] == 'monkeys', I get the PageNotFoundComponent, as expected.
  3. If [requested.region] == 'monkeys' and [requested.resourceType] == 'legislators', I get TypeError: Cannot read property 'legislators' of undefined in my project.

It appears that the || comparison is only looking at the last lookup key rather than both, but it doesn't appear that any combination of brackets, braces, or parentheses seems to extend that comparison to the whole of this.data[requested.region][requested.resourceType].

What am I missing?


Solution

  • For any other newbs out there, as @Nit pointed out, JavaScript doesn't currently support so-called "Optional Chaining"; the (sadly quite ugly) "solution" was to side step the issue with an if/else check on the first parameter, like so:

      public getData = (requested: RouteParameters) => {
        if (this.regions.includes(requested.region))
          return this.components[requested.region][requested.resourceType] || this.notFound;
        else return this.notFound;
      }