title: Accept which array method by caller in typescript
body: <p><strong>Background:</strong></p>
  
  <p>The only difference between the following functions is:</p>
  
  <ul>
  <li><code>createGrid</code> uses <code>map</code> (taking a callback returning type <code>T</code>) and returns <code>T[][]</code></li>
  <li><code>visitGridCoordinates</code> uses <code>forEach</code> (taking a callback returning type <code>void</code>) and returns <code>void</code>.</li>
  </ul>
  
  <pre><code>const createGrid = &lt;T&gt;(width: number, height: number, callback: (x: number, y:number) =&gt; T) =&gt;
    Array
      .from(Array(width).keys())
      .map(
        (x: number) =&gt; Array
          .from(Array(height).keys())
          .map((y: number) =&gt; callback(x, y))
      );
  
  const visitGridCoordinates = (width: number, height: number, callback: (x: number, y:number) =&gt; void) =&gt;
    Array
      .from(Array(width).keys())
      .forEach(
        (x: number) =&gt; Array
          .from(Array(height).keys())
          .forEach((y: number) =&gt; callback(x, y);)
      );
  </code></pre>
  
  <p><strong>Question:</strong></p>
  
  <p>Is there a way to create a wrapper function over these that takes which method to use as an argument? I tried several things but kept running into problems.</p>
  
  <pre><code>const createGrid = verbGrid&lt;string&gt;(Array.prototype.map); // or ('map') alternately
  const visitGridCoordinates = verbGrid(Array.prototype.forEach); // or ('forEach') alternately
  
  const verbGrid = ???
  </code></pre>
  
  <p>I tried writing such a function, then used "infer parameter types from usages" and the result <em>almost</em> works:</p>
  
  <pre><code>const verbGrid = &lt;U&gt;(arrayMethod: (callbackfn: (value: any, index: number, array: any[]) =&gt; void, thisArg?: any) =&gt; void) =&gt; (
    width: number,
    height: number,
    callback: ((x: number, y:number) =&gt; U) | ((x: number, y:number) =&gt; boolean)
  ) =&gt; {
    const result: void | U[][] = arrayMethod.call(
      Array.from(Array(width).keys()),
      (x: number) =&gt; arrayMethod.call(
        Array.from(Array(height).keys()),
        (y: number) =&gt; callback(x, y)
      )
    )
    return result;
  };
  </code></pre>
  
  <p>But when I try to use <code>createGrid</code> its return type is always only <code>void</code>. And of course it is, because the type of <code>arrayMethod</code> says it returns <code>void</code>. When I try using unioned types for the entire type descriptor or just for the return value, various different errors occur.</p>
  
  <p>I played around with using <code>varof</code> as in <code>varof Array&lt;number&gt;["map"] | varof Array&lt;number&gt;["forEach"]</code> to get more explicit with the types and avoid having to re-describe both method types. However I still had no luck (and I notice the <code>map</code> version doesn't specify <code>U</code> anywhere and I don't know how to do that).</p>
  
  <p>Is this even possible, and if so, do you mind helping me understand where I'm going wrong?</p>
  
  <p>Various results I've had:</p>
  
  <ul>
  <li>The result of <code>verbGrid</code> being type <code>unknown</code>.</li>
  <li>No errors in <code>verbGrid</code> but being unable to assign the result to a variable of type <code>U[][]</code> at the call site.</li>
  <li>Passing in <code>'map'</code> and <code>'forEach'</code> as strings and using them as <code>[method]</code> (instead of doing <code>method.call</code>).</li>
  </ul>
  
  <p>I tried to simplify things a little like so:</p>
  
  <pre><code>type ValueReturning = &lt;T, U&gt;(callbackfn: (value: T, index: number, array: T[]) =&gt; U, thisArg?: any) =&gt; U[];
  type VoidReturning = &lt;T&gt;(callbackfn: (value: T, index: number, array: T[]) =&gt; void, thisArg?: any) =&gt; void;
  
  class Enumerable {
    static range(start: number, count: number) {
      return Array.from(Array(count).keys()).map(index =&gt; start + index);
    }
  }
  </code></pre>
  
  <p>But this doesn't work at all ("Type 'ValueReturning' is not generic"):</p>
  
  <pre><code>const verbGrid = &lt;U&gt;(arrayMethod: ValueReturning&lt;number, U&gt; | VoidReturning&lt;number&gt;) =&gt; (
  </code></pre>
  
  <p>Appreciate any guidance.</p>
  
  <p><em>Note: I am new to TypeScript but not new to Generics (from C#).</em></p>
  
  <p><em>Addendum</em></p>
  
  <p>In case it helps, here are the call sites to these two functions.</p>
  
  <pre><code>this._grid = createGrid(width, height, (x: number, y: number) =&gt; {
    const cell = new Cell&lt;string&gt;(x, y);
    this._cells.add(cell);
    return cell;
  });
  visitGridCoordinates(width, height, (x, y) =&gt; {
    getNeighborCoordinates(width, height, x, y)
      .forEach(([neighborX, neighborY]) =&gt; {
        this.grid[x][y].neighbors.add(this._grid[neighborX][neighborY]);
      });
  });
  </code></pre>
  
  <p>It's fine to suggest alternate methods for achieving the same goal, but I really was more interested in learning TypeScript better than I am in fixing this code to be perfectly optimal. (I spent a couple of hours creating a Boggle/Wordament solver last night—it works great and was fun to build.)</p>