title: How to create method that take the keyof interface as an argument, and the arguments of the function excluding the first
body: <h1>the title seems too long but sees my example.</h1>
  <h3>I have this interface</h3>
  <pre><code>interface Types {
      string: (value: string, letterAllowed: string[]) =&gt; boolean;
      number: (value: number, maxNumber: number) =&gt; boolean;
  }
  </code></pre>
  <h3>and this object which uses the interface</h3>
  <pre><code>const types: Types = {
      string: (value: string) =&gt; typeof value === &quot;string&quot;,
      number: (value: number) =&gt; typeof value === &quot;number&quot;,
  };
  </code></pre>
  <h3>and i have this class with this interface</h3>
  <pre><code>interface Check {
      test(type: keyof Types, ...args: any): boolean;
  }
  
  class Check {
      value: any;
  
      constructor(value: any) {
          this.value = value;
      }
  
      test(type, ...args) {
          return types[type](this.value, args);
      }
  }
  </code></pre>
  <h3>what I want is this.</h3>
  <pre><code>// show error, you need to pass key of &quot;Types&quot;
  new Check(&quot;value&quot;).test(&quot;&quot;);
  
  // show error, you need to pass the maxNumber argument
  new Check(5).test(&quot;number&quot;);
  // no errors
  new Check(5).test(&quot;number&quot;, 10);
  
  // show error, you need to pass the letterAllowed argument
  new Check(&quot;value&quot;).test(&quot;string&quot;);
  // show error, letterAllowed is array of strings not number
  new Check(&quot;value&quot;).test(&quot;string&quot;, [1, 2, 3]);
  // no errors
  new Check(&quot;value&quot;).test(&quot;string&quot;, [&quot;a&quot;, &quot;b&quot;, &quot;c&quot;]);
  </code></pre>
  <h3>what I have tried so far is this.</h3>
  <pre><code>interface Types {
      name: (value: string, letterAllowed: string[]) =&gt; string;
  }
  
  type ParametersExceptFirst&lt;F&gt; = F extends (arg0: any, ...rest: infer R) =&gt; any ? R : never;
  
  interface Check {
      &lt;K extends keyof Types&gt;(value: K): Types[K];
  
      &lt;K extends keyof Types&gt;(value: K, ...args: ((R &amp; ((arg0: any, ...rest: R[]) =&gt; any)) | never[])[]): boolean;
  }
  
  const check: Check = (value: any, ...args) =&gt; {
      return true;
  };
  
  // [✅] it shows an error if you don't pass any key of &quot;Types&quot;
  check(&quot;&quot;);
  
  // it doesn't show an error if you didn't pass the second argument
  check(&quot;name&quot;);
  
  // [✅] it shows an error if you pass an array of different types instead of a string
  check(&quot;name&quot;, [1, 2, 3]);
  </code></pre>
  <h3>what I want is how can I improve what I build and use it with a class method</h3>
  <h1>Edit </h1>
  <h3>the solution works but when I add it to class</h3>
  <pre><code>interface Types {
      string: (value: string, letterAllowed: string[]) =&gt; boolean;
      number: (value: number, maxNumber: number) =&gt; boolean;
      boolean: (value: boolean) =&gt; boolean;
  }
  
  const types: Types = {
      string: (value, letterAllowed) =&gt; typeof value === &quot;string&quot;,
      number: (value, maxNumber) =&gt; typeof value === &quot;number&quot;,
      boolean: (value) =&gt; typeof value === &quot;boolean&quot;,
  };
  
  type OmitFirstArgument&lt;T&gt; = T extends (first: any, ...args: infer A) =&gt; any ? A : never;
  
  class Typeof {
      value: any;
  
      constructor(value: any) {
          this.value = value;
      }
  
      is&lt;T extends keyof Types&gt;(type: T, ...args: OmitFirstArgument&lt;Types[T]&gt;): boolean {
          return types[type](this.value, ...args);
      }
  }
  
  
  new Typeof(&quot;sss&quot;).is(&quot;number&quot;,10);
  </code></pre>
  <h3>it shows this error</h3>
  <pre><code>return types[type](this.value, ...args);
  </code></pre>
  <blockquote>
  <p>TS2556: A spread argument must either have a tuple type or be passed to a rest parameter.</p>
  </blockquote>
  <h3>i manage to solve that by using apply</h3>
  <pre><code>return types[type].apply(this, [this.value, ...args]);
  </code></pre>
  <h3>add string as another option to use with keyof Types</h3>
  <pre><code>class TypeOf&lt;T&gt; {
      value: T;
  
      constructor(value: T) {
          this.value = value;
      }
      
      // TODO
    // TS2536: Type 'A' cannot be used to index type 'Types'.
      is&lt;A extends (keyof Types | string)&gt;(name: A, ...args: OmitFirstArgument&lt;Types[A]&gt;) {
          return types[name as any].apply(this, [this.value, ...args]);
      }
  }
  </code></pre>