title: Type safe version of lodash _.get - deconstruct array type conditionally
body: <p>For a long time we've been having a problem that the only way to access a nested property safely and easily is to use <code>_.get</code>. Ex:</p>
  
  <pre><code>_.get(obj, "Some.Nested[2].Property", defaultValue);
  </code></pre>
  
  <p>This works great, but doesn't stand up to property renames as frequently happens. Theoretically, it should be possible to transform the above into the following and allow TypeScript to implicitly type check it:</p>
  
  <pre><code>safeGet(obj, "Some", "Nested", 2, "Property", defaultValue);
  </code></pre>
  
  <p>I've been successful in creating such a typing for everything except for array types:</p>
  
  <pre><code>function getSafe&lt;TObject, P1 extends keyof TObject&gt;(obj: TObject, p1: P1): TObject[P1];
  
  function getSafe&lt;TObject, P1 extends keyof TObject, P2 extends keyof TObject[P1]&gt;(obj: TObject, p1: P1, p2: P2): TObject[P1][P2];
  </code></pre>
  
  <p>This properly checks for items at depth (I will auto generate these statements to 10 levels or so). It fails with array properties because the type passed into the next parameter is <code>T[]</code> and not <code>T</code>.</p>
  
  <p>The complexity or verbosity of any solution is of no consideration as the code will be auto generated, the problem is that I can't seem to find any combination of type declarations which will allow me to accept an integer parameter and deconstruct the array type moving forward. </p>
  
  <p>You can deconstruct an array (where <code>T</code> is an array) using <code>T[number]</code>. The problem is that I have no way to constrain where <code>T</code> is an array on a nested property.</p>
  
  <pre><code>function getSafe&lt;TObject, P1 extends keyof TObject, P2 extends keyof TObject[P1][number]&gt;(obj: TObject, p1: P1, index: number, p2: P2): TObject[P1][number][P2];
                                                                                   ^^^^^^                                                             ^^^^^^
  const test2 = getSafe(obj, "Employment", 0, "Id"); // example usage
  </code></pre>
  
  <p>That actually works at the call-site (no errors there, correctly gives us param and return types), but gives us an error in the declaration itself because you can't index <code>TObject[P1]</code> with <code>[number]</code> as we can't guarantee <code>TObject[P1]</code> is an array. </p>
  
  <p>(<em>Note: <code>TType[number]</code> is a viable way to get the element type from an array type, but we need to convince the compiler that we're doing this to an array</em>)</p>
  
  <p>The question is really, would there be away to add a array constraint to <code>TObject[P1]</code> <em>or</em> is there another way to do this that I'm missing.</p>