簡體   English   中英

使用泛型的Typescript箭頭函數的語法錯誤

[英]Syntax error for Typescript arrow functions with generics

首先,這里有一個類似的問題: 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中的 on1on2 - 函數on1有更多代碼。

所以這是我的代碼示例。


情況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
        });
    }
}

函數on1給出了以下錯誤:

類型'(講座:講座,oldLecture:Lecture)=> void'的參數不能賦予類型'的參數((講座:T,oldLecture:T)=> void)| ((name:string,... args:any [])=> void)'。 類型'(講座:講座,oldLecture:Lecture)=> void'不能分配給'(name:string,... args:any [])=> void'。 參數“講座”和“名稱”的類型不兼容。 類型'字符'不能分配給'Lecture'類型。

函數on2給出以下錯誤:

類型'(講座:講座,oldLecture:Lecture)=> void'的參數不能分配給'(講座:T,oldLecture:T)=> void'類型的參數。 參數'講座'和'講座'的類型是不相容的。 類型'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):

但我仍然想知道這個問題的確切原因。

我知道這不能直接回答你的問題,但你可以通過使用類方法來避免這個問題,而不是嵌套的匿名回調(感覺非常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) => {

})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM