title: Restricting parameter to keys of type that return a value of a type or a function that does the same
body: <p>From a high level, I'm trying to define a generic type taking two types:</p>
  <ul>
  <li>T - The type</li>
  <li>V - The type of a value returned when accessing T with a key of T</li>
  </ul>
  <p>Such that it allows a union of:</p>
  <ul>
  <li>Any keys of type T which return the type V</li>
  <li>A function that takes an instance of type T and returns a value of type V</li>
  </ul>
  <p>To that end, I've defined the following:</p>
  <pre><code>type KeysWithValueOfType&lt;T, V&gt; = {
      [K in keyof T]-?: Exclude&lt;T[K], undefined | null&gt; extends V ? K : never
  }[keyof T]
  </code></pre>
  <p>Which is taken from here:</p>
  <p><a href="https://stackoverflow.com/a/54520829/50776">https://stackoverflow.com/a/54520829/50776</a></p>
  <p>Then, I define a selector type which is the union of the key and the functional accessor:</p>
  <pre><code>type Selector&lt;T, V&gt; = KeysWithValueOfType&lt;T, V&gt; | ((t: T) =&gt; V)
  </code></pre>
  <p>At this point, I want to when trying to create a generic function to resolve the accessor to a value given an instance of type T</p>
  <pre><code>function getValue&lt;Data extends Aggregate, Result&gt;(
      selector: Selector&lt;Data, Result&gt;,
      data: Data
  ): Result {
      // If a function, evaluate, otherwise, use as a key
      // into the object.
      return typeof selector === 'function' ? selector(data) : data[selector]
  }
  </code></pre>
  <p>However, it gives me the following error:</p>
  <pre><code>Type 'Result | Data[KeysWithValueOfType&lt;Data, Result&gt;]' is not assignable to type 'Result'.
    'Result' could be instantiated with an arbitrary type which could be unrelated to 'Result | Data[KeysWithValueOfType&lt;Data, Result&gt;]'.ts(2322)
  </code></pre>
  <p>If I try and decompose the ternary operator:</p>
  <pre><code>function getValue&lt;Data extends Aggregate, Result&gt;(
      selector: Selector&lt;Data, Result&gt;,
      data: Data
  ): Result {
      // If the accessor is a string, evaluate and return it.
      if (typeof selector === 'function')
          return selector(data)
  
      // Use the accessor
      return data[selector]
  }
  </code></pre>
  <p>It looks like the line:</p>
  <pre><code>return data[selector]
  </code></pre>
  <p>I get a slightly different message:</p>
  <pre><code>Type 'Data[KeysWithValueOfType&lt;Data, Result&gt;]' is not assignable to type 'Result'.
    'Result' could be instantiated with an arbitrary type which could be unrelated to 'Data[KeysWithValueOfType&lt;Data, Result&gt;]'.ts(2322)
  </code></pre>
  <p>Is there a way to accomplish what I'm looking for?</p>
  <p>I am currently using Typescript 4.6.3.</p>
  <p>I've also created a code sandbox which shows the issue, the error is in <code>getValue</code> towards the end:</p>
  <p><a href="https://codesandbox.io/s/selector-example-0gbfhm?file=/src/index.ts" rel="nofollow noreferrer">https://codesandbox.io/s/selector-example-0gbfhm?file=/src/index.ts</a></p>