title: Resolve object recursively with type safe property access in two steps
body: <p>I'm trying to replace the string types in the following function with more specific types that ensure type safe property access:</p>
  <pre><code>import {get} from 'lodash';
  
  const obj = {
    foo: 'foo',
    bar: {
      a: 'Hello',
      b: {c: 'World'}
    }
  };
  
  function factory(namespace?: string) {
    return function getter(key: string) {
      return get(obj, [namespace, key].filter((part) =&gt; part != null).join('.'));
    };
  }
  
  const getter = factory('bar');
  getter('b.c'); // 'World'
  </code></pre>
  <p>The dot notation indicates a nested property access. It can be present both in the <code>namespace</code> as well as in the <code>key</code>.</p>
  <p>So far I've found out that I can type <code>namespace</code> with this utility:</p>
  <pre><code>type NestedKeyOf&lt;ObjectType extends object&gt; =
    {
      [Key in keyof ObjectType &amp; (string | number)]: ObjectType[Key] extends object
        ? `${Key}` | `${Key}.${NestedKeyOf&lt;ObjectType[Key]&gt;}`
        : `${Key}`
    }[keyof ObjectType &amp; (string | number)];
  </code></pre>
  <p>Usage: <code>namespace?: NestedKeyOf&lt;typeof obj&gt;</code>.</p>
  <p>I'm struggling however to come up with a dynamic type that is automatically assigned to <code>key</code>.</p>
  <p>Two additional requirements would be:</p>
  <ol>
  <li>A namespace should only ever resolve to an object (no leaf strings).</li>
  <li>A getter should always resolve to a leaf string (no objects).</li>
  </ol>
  <p>It can be assumed that only objects and strings are present in the object, nothing else.</p>
  <pre><code>// Test cases
  
  // Should pass
  factory()('foo')
  factory('bar')('a')
  factory('bar')('b.c')
  
  // Invalid property access
  // @ts-expect-error 
  factory('baz')
  // @ts-expect-error
  factory('bar')('d')
  
  // Only partial namespaces are allowed
  // @ts-expect-error 
  factory('foo')
  
  // Getter calls need to resolve to a leaf string
  // @ts-expect-error
  factory('bar')('b')
  </code></pre>
  <p>Any help would be really appreciated! Many thanks!</p>