title: In TypeScript, how can I infer my arguments and impose a constraint that all items be keyof T, where T is the generic type for the function?
body: <p>My goal here is to create a function named: <code>getFields</code>. This function has a generic <code>&lt;T&gt;</code> and a parameter <code>...fields: Array&lt;keyof T&gt;</code>. I would like this function to return a function which when given an object of type <code>&lt;T&gt;</code> will return a reduced object with only the properties named in <code>...fields</code>.</p>
  <p>The following is one helper type and my <code>getFields</code> implementation:</p>
  <pre class="lang-js prettyprint-override"><code>type SubObj&lt;T, S extends Array&lt;keyof T&gt;&gt; = Pick&lt;
    T,
    keyof { [K in S[number]]: K extends keyof T ? K : never }
  &gt;;
  
  export function getFields&lt;T extends Record&lt;string, unknown&gt;&gt;(
    ...fields: Array&lt;keyof T&gt;
  ): (obj: T) =&gt; SubObj&lt;T, typeof fields&gt; {
    return (obj: T) =&gt;
      Object.fromEntries(fields.map((field) =&gt; [field, obj[field]])) as SubObj&lt;
        T,
        typeof fields
      &gt;;
  }
  </code></pre>
  <p>I tested this implementation with the following code:</p>
  <pre class="lang-js prettyprint-override"><code>type A = {
    a: string;
    b: string;
    c: string;
  };
  
  const b = getFields&lt;A&gt;('a', 'c')({ a: '', b: '', c: '' });
  </code></pre>
  <p>However, when I look at the <code>typeof</code> <code>b</code> it is <code>Pick&lt;A, &quot;a&quot; | &quot;b&quot; | &quot;c&quot;&gt;</code>. What I really want is <code>Pick&lt;A, &quot;a&quot; | &quot;c&quot;&gt;</code>.</p>
  <p>I have tried a lot of things to make this work the way I intend it to, but the only success was adding a second generic argument which would require me to change the code to this:</p>
  <pre class="lang-js prettyprint-override"><code>const b = getFields&lt;A, ['a','c']&gt;('a', 'c')({ a: '', b: '', c: '' });
  </code></pre>
  <p>This is too redundant for me to see as acceptable.</p>
  <p>At this point, I think I've hit the limits of my TypeScript abilities because I can't think of any other way to accomplish what I'm looking for.</p>
  <p>Is this even possible to do with TypeScript? If so, what do I need to do?</p>