title: Syntax error for Typescript arrow functions with generics
body: <p>First of all, there is a similar question here: <a href="https://stackoverflow.com/questions/32308370/what-is-the-syntax-for-typescript-arrow-functions-with-generics">what-is-the-syntax-for-typescript-arrow-functions-with-generics</a></p>
  
  <p>But, I'd like to know the <strong>culprit</strong> of the syntax error.</p>
  
  <p>I am using an external library, and this is what the definition file <em>(index.d.ts)</em> looks like:</p>
  
  <hr>
  
  <h2>External Library's index.d.ts</h2>
  
  <pre><code>declare namespace Student {
      export interface Lecture {
          lectureName: string;
      }
  
      export interface Student {
          new (): Student;
  
          on1(eventName: string, callback: (&lt;T&gt;(lecture: T, oldLecture: T) =&gt; void) |
                                          ((name: string, ...args: any[]) =&gt; void)): void;
  
          on2(eventName: string, callback: (&lt;T&gt;(lecture: T, oldLecture: T) =&gt; void)): void;
      }
  }
  
  declare var Student: Student.Student;
  
  declare module "student" {
      export = Student;
  }
  </code></pre>
  
  <p>Note that there are two functions: <em>on1</em> and <em>on2</em> in <em>Student.Student</em> - the function <em>on1</em> has a bit more code.</p>
  
  <p>So here are my code examples.</p>
  
  <hr>
  
  <h2>Case 1</h2>
  
  <pre><code>import * as Student from 'student';
  import { Lecture } from 'student';
  
  export class MyStudent { 
      student: Student.Student;
  
      constructor() {
          this.student = new Student();
  
          this.student.on1('test', (lecture: Lecture, oldLecture: Lecture) =&gt; {
              // Argument of type error
          });
  
          this.student.on2('test', (lecture: Lecture, oldLecture: Lecture) =&gt; {
              // Argument of type error
          });
      }
  }
  </code></pre>
  
  <p>The function <em>on1</em> gives the below error:</p>
  
  <blockquote>
    <p>Argument of type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to parameter of type '((lecture: T, oldLecture: T) => void) | ((name: string, ...args: any[]) => void)'.
      Type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to type '(name: string, ...args: any[]) => void'.
        Types of parameters 'lecture' and 'name' are incompatible.
          Type 'string' is not assignable to type 'Lecture'.</p>
  </blockquote>
  
  <p>The function <em>on2</em> gives the below error:</p>
  
  <blockquote>
    <p>Argument of type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to parameter of type '(lecture: T, oldLecture: T) => void'.
      Types of parameters 'lecture' and 'lecture' are incompatible.
        Type 'T' is not assignable to type 'Lecture'.</p>
  </blockquote>
  
  <p>I thought this example is the right way to implement the code - but why this gives an error?</p>
  
  <hr>
  
  <h2>Case 2</h2>
  
  <pre><code>import * as Student from 'student';
  import { Lecture } from 'student';
  
  export class MyStudent { 
      student: Student.Student;
  
      constructor() {
          this.student = new Student();
  
          this.student.on1('test', &lt;Lecture&gt;(lecture: Lecture, oldLecture: Lecture) =&gt; {
              lecture.lectureName; 
              // Error: Property 'lectureName' does not exist on type 'Lecture'
          });
  
          this.student.on2('test', &lt;Lecture&gt;(lecture: Lecture, oldLecture: Lecture) =&gt; {
              lecture.lectureName;
              // Error: Property 'lectureName' does not exist on type 'Lecture'
          });
      }
  }
  </code></pre>
  
  <p>In this example, I put <code>&lt;Lecture&gt;</code> in front of the arrow function - so there is no error in the implementation, but now I cannot use <code>lecture.lectureName</code> at all.  Why?</p>
  
  <hr>
  
  <h2>Case 3</h2>
  
  <pre><code>import * as Student from 'student';
  import { Lecture } from 'student';
  
  export class MyStudent { 
      student: Student.Student;
  
      constructor() {
          this.student = new Student();
  
          this.student.on1('test', &lt;T extends Lecture&gt;(lecture: T, oldLecture: T) =&gt; {
              lecture.lectureName; // Yay! No problem!
          });
  
          this.student.on2('test', &lt;T extends Lecture&gt;(lecture: T, oldLecture: T) =&gt; {
              // Argument of type error
          });
      }
  }
  </code></pre>
  
  <p>So this example has <strong>the correct answer</strong> - however, the function <em>on2</em> still gives the argument of type error, just like the case 1's example.  Shouldn't it be okay since the function <em>on1</em> is okay?</p>
  
  <hr>
  
  <h2>Case 4</h2>
  
  <pre><code>import * as Student from 'student';
  import { Lecture } from 'student';
  
  export class MyStudent { 
      student: Student.Student;
  
      constructor() {
          this.student = new Student();
  
          this.student.on1('test', () =&gt; () =&gt; (lecture: Lecture, oldLecture: Lecture) =&gt; {
              lecture.lectureName; // Yay! No error!
          });
  
          this.student.on2('test', () =&gt; () =&gt; (lecture: Lecture, oldLecture: Lecture) =&gt; {
              lecture.lectureName; // Yay! No error!
          });
      }
  }
  </code></pre>
  
  <p>I found this solution accidentally - and both functions are working fine.  But I have no idea why this is working.</p>
  
  <hr>
  
  <p>I spent some time trying to figure out the exact cause by looking at these references (because I love TypeScript):</p>
  
  <ul>
  <li><a href="https://github.com/teppeis/typescript-spec-md/blob/master/en/ch04.md" rel="nofollow noreferrer">https://github.com/teppeis/typescript-spec-md/blob/master/en/ch04.md</a></li>
  <li><a href="https://basarat.gitbooks.io/typescript/content/docs/types/generics.html" rel="nofollow noreferrer">https://basarat.gitbooks.io/typescript/content/docs/types/generics.html</a></li>
  <li><a href="https://github.com/Microsoft/TypeScript/issues/3323" rel="nofollow noreferrer">https://github.com/Microsoft/TypeScript/issues/3323</a></li>
  <li><a href="https://stackoverflow.com/questions/40270393/specify-return-type-in-typescript-arrow-function">Specify return type in TypeScript arrow function</a></li>
  </ul>
  
  <p>but I am still wondering the exact cause of this issue.</p>