带有泛型的 Typescript 箭头函数的语法错误
Syntax error 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[=83=中有两个函数: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 给出以下错误:
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'.
函数 on2 给出以下错误:
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'.
我认为这个示例是实现代码的正确方法 - 但为什么会出现错误?
案例二
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
。为什么?
案例三
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
但我仍然想知道这个问题的确切原因。
我知道这不能直接回答你的问题,但你可以通过使用 class 方法来避免这个问题,而不是嵌套的匿名回调(感觉很 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)
}
}
您对如何声明通用函数以及如何调用通用函数感到有点困惑。
您可以这样总结您的问题:
// 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
在您的示例中,您实现了请求的回调,这意味着当有人调用此回调时,她将知道参数类型。
记住,你不是在调用回调,你只是在执行它!
因此您的代码应如下所示:
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
});
}
}
问题是输入在错误的地方声明了泛型:
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) => {
})
首先这里有个类似的问题:
但是,我想知道语法错误的罪魁祸首。
我正在使用外部库,这是定义文件 (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[=83=中有两个函数: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 给出以下错误:
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'.
函数 on2 给出以下错误:
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'.
我认为这个示例是实现代码的正确方法 - 但为什么会出现错误?
案例二
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
。为什么?
案例三
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
但我仍然想知道这个问题的确切原因。
我知道这不能直接回答你的问题,但你可以通过使用 class 方法来避免这个问题,而不是嵌套的匿名回调(感觉很 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)
}
}
您对如何声明通用函数以及如何调用通用函数感到有点困惑。
您可以这样总结您的问题:
// 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
在您的示例中,您实现了请求的回调,这意味着当有人调用此回调时,她将知道参数类型。
记住,你不是在调用回调,你只是在执行它!
因此您的代码应如下所示:
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
});
}
}
问题是输入在错误的地方声明了泛型:
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) => {
})