【发布时间】:2018-01-31 06:14:22
【问题描述】:
首先这里有一个类似的问题:what-is-the-syntax-for-typescript-arrow-functions-with-generics
但是,我想知道语法错误的罪魁祸首。
我正在使用外部库,这是定义文件 (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;
}
注意Student.Student中有两个函数:on1和on2——函数on1有多一点代码。
这是我的代码示例。
案例一
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
});
}
}
函数 on1 给出以下错误:
'(lecture: Lecture, oldLecture: Lecture) => void' 类型的参数不能分配给 '((lecture: T, oldLecture: T) => void) 类型的参数 | ((name: string, ...args: any[]) => void)'。 类型 '(lecture: Lecture, oldLecture: Lecture) => void' 不可分配给类型 '(name: string, ...args: any[]) => void'。 参数 'lecture' 和 'name' 的类型不兼容。 类型“字符串”不可分配给类型“讲座”。
函数 on2 给出以下错误:
“(lecture: Lecture, oldLecture: Lecture) => void”类型的参数不能分配给“(lecture: T, oldLecture: T) => void”类型的参数。 参数 'lecture' 和 'lecture' 的类型不兼容。 类型“T”不能分配给类型“Lecture”。
我认为这个示例是实现代码的正确方法 - 但为什么会报错?
案例 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'
});
}
}
在这个例子中,我把<Lecture>放在了箭头函数的前面——所以实现中没有错误,但现在我根本不能使用lecture.lectureName。为什么?
案例 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
});
}
}
所以这个例子有正确答案 - 但是,函数 on2 仍然给出类型错误的参数,就像案例 1 的例子一样。既然函数on1没问题,应该没问题吧?
案例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!
});
}
}
我偶然发现了这个解决方案 - 两个功能都运行良好。但我不知道为什么会这样。
我花了一些时间试图通过查看这些参考来找出确切的原因(因为我喜欢 TypeScript):
- https://github.com/teppeis/typescript-spec-md/blob/master/en/ch04.md
- https://basarat.gitbooks.io/typescript/content/docs/types/generics.html
- https://github.com/Microsoft/TypeScript/issues/3323
- Specify return type in TypeScript arrow function
但我仍然想知道这个问题的确切原因。
【问题讨论】:
标签: typescript generics typescript-typings arrow-functions