简体   繁体   English

使用泛型的Typescript箭头函数的语法错误

[英]Syntax error for Typescript arrow functions with generics

First of all, there is a similar question here: what-is-the-syntax-for-typescript-arrow-functions-with-generics 首先,这里有一个类似的问题: what-is-the-syntax-for-typescript-arrow-functions-with-generics

But, I'd like to know the culprit of the syntax error. 但是,我想知道语法错误的罪魁祸首

I am using an external library, and this is what the definition file (index.d.ts) looks like: 我正在使用外部库,这就是定义文件(index.d.ts)的样子:


External Library's index.d.ts 外部图书馆的index.d.ts

declare namespace Student {
    export interface Lecture {
        lectureName: string;
    }

    export interface Student {
        new (): Student;

        on1(eventName: string, callback: (<T>(lecture: T, oldLecture: T) => void) |
                                        ((name: string, ...args: any[]) => void)): void;

        on2(eventName: string, callback: (<T>(lecture: T, oldLecture: T) => void)): void;
    }
}

declare var Student: Student.Student;

declare module "student" {
    export = Student;
}

Note that there are two functions: on1 and on2 in Student.Student - the function on1 has a bit more code. 请注意,有两个函数: Student.Student中的 on1on2 - 函数on1有更多代码。

So here are my code examples. 所以这是我的代码示例。


Case 1 情况1

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) => {
            // Argument of type error
        });

        this.student.on2('test', (lecture: Lecture, oldLecture: Lecture) => {
            // Argument of type error
        });
    }
}

The function on1 gives the below error: 函数on1给出了以下错误:

Argument of type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to parameter of type '((lecture: T, oldLecture: T) => void) | 类型'(讲座:讲座,oldLecture:Lecture)=> void'的参数不能赋予类型'的参数((讲座:T,oldLecture:T)=> void)| ((name: string, ...args: any[]) => void)'. ((name:string,... args:any [])=> void)'。 Type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to type '(name: string, ...args: any[]) => void'. 类型'(讲座:讲座,oldLecture:Lecture)=> void'不能分配给'(name:string,... args:any [])=> void'。 Types of parameters 'lecture' and 'name' are incompatible. 参数“讲座”和“名称”的类型不兼容。 Type 'string' is not assignable to type 'Lecture'. 类型'字符'不能分配给'Lecture'类型。

The function on2 gives the below error: 函数on2给出以下错误:

Argument of type '(lecture: Lecture, oldLecture: Lecture) => void' is not assignable to parameter of type '(lecture: T, oldLecture: T) => void'. 类型'(讲座:讲座,oldLecture:Lecture)=> void'的参数不能分配给'(讲座:T,oldLecture:T)=> void'类型的参数。 Types of parameters 'lecture' and 'lecture' are incompatible. 参数'讲座'和'讲座'的类型是不相容的。 Type 'T' is not assignable to type 'Lecture'. 类型'T'不能分配给'Lecture'类型。

I thought this example is the right way to implement the code - but why this gives an error? 我认为这个例子是实现代码的正确方法 - 但为什么会出错呢?


Case 2 案例2

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: Lecture, oldLecture: Lecture) => {
            lecture.lectureName; 
            // Error: Property 'lectureName' does not exist on type 'Lecture'
        });

        this.student.on2('test', <Lecture>(lecture: Lecture, oldLecture: Lecture) => {
            lecture.lectureName;
            // Error: Property 'lectureName' does not exist on type 'Lecture'
        });
    }
}

In this example, I put <Lecture> in front of the arrow function - so there is no error in the implementation, but now I cannot use lecture.lectureName at all. 在这个例子中,我将<Lecture>放在箭头函数前面 - 所以实现中没有错误,但现在我根本不能使用lecture.lectureName Why? 为什么?


Case 3 案例3

import * as Student from 'student';
import { Lecture } from 'student';

export class MyStudent { 
    student: Student.Student;

    constructor() {
        this.student = new Student();

        this.student.on1('test', <T extends Lecture>(lecture: T, oldLecture: T) => {
            lecture.lectureName; // Yay! No problem!
        });

        this.student.on2('test', <T extends Lecture>(lecture: T, oldLecture: T) => {
            // Argument of type error
        });
    }
}

So this example has the correct answer - however, the function on2 still gives the argument of type error, just like the case 1's example. 所以这个例子有正确的答案 - 但是,函数on2仍然给出了类型错误的参数,就像案例1的例子一样。 Shouldn't it be okay since the function on1 is okay? 不应该没关系,因为on1功能还可以吗?


Case 4 案例4

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) => {
            lecture.lectureName; // Yay! No error!
        });

        this.student.on2('test', () => () => (lecture: Lecture, oldLecture: Lecture) => {
            lecture.lectureName; // Yay! No error!
        });
    }
}

I found this solution accidentally - and both functions are working fine. 我偶然发现了这个解决方案 - 两个功能都运行正常。 But I have no idea why this is working. 但我不知道为什么这样做。


I spent some time trying to figure out the exact cause by looking at these references (because I love TypeScript): 我花了一些时间试图通过查看这些引用来找出确切的原因(因为我喜欢TypeScript):

but I am still wondering the exact cause of this issue. 但我仍然想知道这个问题的确切原因。

I know this doesn't answer your question directly but you can avoid this issue by using class methods, instead of nested anonymous callbacks (which feels very 2015) 我知道这不能直接回答你的问题,但你可以通过使用类方法来避免这个问题,而不是嵌套的匿名回调(感觉非常2015)

type Handler = <T>(t: T) => void;

class Student {
  on1(s:string, callback:Handler) : void {
    callback<string>("hi")
  }
}

class MyStudent { 
    student: Student

    constructor() {
        this.student = new Student()
        this.student.on1('test', this.log)
    }

    log<T>(t:T) : void { 
         console.log("hi " + t)
    }
}

You are a bit confused by how to declare a generic function and how to call a generic function. 您对如何声明泛型函数以及如何调用泛型函数感到有点困惑。

You can summarize your issue with this: 您可以用以下方法总结您的问题:

// Define the Identity function type
// The result type = input type
type TIdentityFunc = <T>(input: T) => T;

// Implement the TIdentity function
// We followed the rule.
const identityImpl: TIdentityFunc = <T>(input: T) => input;

// Now we call this implementation
const num = identity(5);   // num is always number
const str = identity('hi') // str is always a string

In your example you implemented the requested callback, this means that when someone will call this callback, she will know the parameters types. 在您的示例中,您实现了请求的回调,这意味着当有人调用此回调时,她将知道参数类型。

Remember, you are not calling the callback, you are only implementing it! 记住,你没有打电话给回调,你只是在实现它!

So your code should look like this: 所以你的代码应该是这样的:

import * as Student from 'student';
import { Lecture } from 'student';

export class MyStudent {
  student: Student.Student;

  constructor() {
    this.student = new Student();

    this.student.on1('test', <T>(l1: T | string, l2: T, ...args) => {
      // This is a bit complicated overloading, 
      // But it follows the rules of the declaration
    });

    this.student.on2('test', <T>(lecture: T, oldLecture: T) => {
      // Your only assumption is that lecture, and oldLecture are the same type
    });
  }
}

The problem is the typing was declaring the generic at the wrong place: 问题是打字是在错误的地方声明通用:

declare interface Lecture {
  lectureName: string;
}

declare interface Student {
  new (): Student;

  on1<T>(eventName: string, callback: ((lecture: T, oldLecture: T) => void) |
    ((name: string, ...args: any[]) => void)): void;
  on2<T>(eventName: string, callback: (lecture: T, oldLecture: T) => void): void;
}

let s: Student;

s.on1('x', (a: Lecture, b: Lecture) => {

})
s.on2('y', (a: string, b: string) => {

})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM