typescript: วิธีกำหนดประเภทสำหรับการเรียกฟังก์ชัน (เป็นฟังก์ชันประเภทใดก็ได้, ไม่ใช่ Universal ใด ๆ ) ที่ใช้ในพารามิเตอร์ method


313

ขณะนี้ฉันมีคำจำกัดความประเภทเป็น:

interface Param {
    title: string;
    callback: any;
}

ฉันต้องการบางสิ่งเช่น:

interface Param {
    title: string;
    callback: function;
}

แต่คนที่สองไม่ได้รับการยอมรับ

คำตอบ:


285

ประเภททั่วโลกFunctionทำหน้าที่จุดประสงค์นี้

นอกจากนี้หากคุณต้องการเรียกใช้การเรียกกลับนี้ด้วย 0 อาร์กิวเมนต์และจะละเว้นค่าที่ส่งคืนชนิดนี้จะ() => voidจับคู่กับฟังก์ชันทั้งหมดที่ไม่มีอาร์กิวเมนต์


27
สิ่งนี้ขาดหายไปในรูปแบบพื้นฐาน
Yogesh

13
ไม่ใช่ประเภทพื้นฐานเพราะคุณควรกำหนดอาร์กิวเมนต์และส่งคืนค่า การโทรกลับ: (number: number) => void; มีประโยชน์มากกว่าสำหรับการตรวจสอบประเภทมากกว่าการเรียกกลับ: function; อยากจะเป็น.
kpup

@kpup เพื่อความชัดเจนคุณกำลังบอกว่าจะไม่ใช้ตัวพิมพ์ใหญ่ F Functionตามที่แสดงในบรรทัดแรกของคำตอบนี้และบอกวรรคที่สอง (โดยใช้ประเภทของ() => voidหรือสิ่งที่ตรงกับกรณีใช้งาน)
ruffin

2
FWIW เอกสารประเภทฟังก์ชั่นที่มีอยู่ที่นี่
imjared

191

typescript จาก v1.4 มีtypeคำหลักที่ประกาศชื่อแทนประเภท (คล้ายกับ a typedefใน C / C ++) คุณสามารถประกาศประเภทการโทรกลับของคุณดังนี้:

type CallbackFunction = () => void;

ซึ่งประกาศฟังก์ชั่นที่ไม่มีการโต้แย้งและไม่ส่งคืนสิ่งใด ฟังก์ชั่นที่รับค่าศูนย์หรือมากกว่าอาร์กิวเมนต์ประเภทใด ๆ และส่งคืนไม่มีอะไรจะเป็น:

type CallbackFunctionVariadic = (...args: any[]) => void;

จากนั้นคุณสามารถพูดเช่น

let callback: CallbackFunctionVariadic = function(...args: any[]) {
  // do some stuff
};

หากคุณต้องการฟังก์ชั่นที่รับจำนวนอาร์กิวเมนต์โดยพลการและส่งคืนสิ่งใด ๆ (รวมถึงโมฆะ):

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any;

คุณสามารถระบุอาร์กิวเมนต์ที่จำเป็นบางส่วนจากนั้นชุดของอาร์กิวเมนต์เพิ่มเติม (เช่นสตริงตัวเลขและชุดของอาร์กิวเมนต์พิเศษ):

type CallbackFunctionSomeVariadic =
  (arg1: string, arg2: number, ...args: any[]) => void;

สิ่งนี้มีประโยชน์สำหรับสิ่งต่างๆเช่นตัวจัดการ EventEmitter

ฟังก์ชั่นสามารถพิมพ์ได้มากตามที่คุณต้องการในแบบนี้ถึงแม้ว่าคุณสามารถดำเนินการและประสบปัญหา combinatoric ถ้าคุณพยายามที่จะตอกย้ำทุกอย่างด้วยนามแฝงประเภท


1
ระหว่างFunctionและ(...args: any[]) => anyต้องการอะไร
Ahong

@ Ahong: โดยส่วนตัวแล้วฉันชอบที่จะให้หลังเพราะมันมีลายเซ็น ... ปกติ ...args: any[]ไม่มีประโยชน์มาก
Ed S.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;สิ่งที่ฉันกำลังมองหา
aqteifan

61

จากคำตอบของไรอันฉันคิดว่าอินเทอร์เฟซที่คุณกำลังค้นหาถูกกำหนดไว้ดังนี้:

interface Param {
    title: string;
    callback: () => void;
}

34

นี่คือตัวอย่างของฟังก์ชันที่รับการเรียกกลับ

const sqk = (x: number, callback: ((_: number) => number)): number => {
  // callback will receive a number and expected to return a number
  return callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  return x;       // we must return a number here
});

หากคุณไม่สนใจเกี่ยวกับค่าตอบแทนของการโทรกลับ (คนส่วนใหญ่ไม่ทราบวิธีการใช้ประโยชน์ในวิธีที่มีประสิทธิภาพ) คุณสามารถใช้ void

const sqk = (x: number, callback: ((_: number) => void)): void => {
  // callback will receive a number, we don't care what it returns
  callback (x * x);
}

// here our callback will receive a number
sqk(5, function(x) {
  console.log(x); // 25
  // void
});

หมายเหตุลายเซ็นที่ฉันใช้สำหรับcallbackพารามิเตอร์ ...

const sqk = (x: number, callback: ((_: number) => number)): number

ฉันจะบอกว่านี่เป็นข้อบกพร่องของ TypeScript เพราะเราคาดว่าจะให้ชื่อสำหรับพารามิเตอร์การโทรกลับ ในกรณีนี้ฉันใช้_เพราะมันใช้งานไม่ได้ในsqkฟังก์ชั่น

อย่างไรก็ตามถ้าคุณทำเช่นนี้

// danger!! don't do this
const sqk = (x: number, callback: ((number) => number)): number

เป็นTypeScript ที่ถูกต้องแต่จะตีความว่า ...

// watch out! typescript will think it means ...
const sqk = (x: number, callback: ((number: any) => number)): number

เช่น typescript จะคิดว่าพารามิเตอร์ชื่อเป็นและประเภทโดยนัยคือnumber anyเห็นได้ชัดว่านี่ไม่ใช่สิ่งที่เราตั้งใจ แต่อนิจจานั่นคือวิธีที่ TypeScript ทำงาน

ดังนั้นอย่าลืมระบุชื่อพารามิเตอร์เมื่อพิมพ์พารามิเตอร์ฟังก์ชั่นของคุณ ... งี่เง่าเพราะมันอาจดูเหมือน


32

คุณสามารถกำหนดประเภทฟังก์ชั่นในส่วนต่อประสานได้หลายวิธี

  1. วิธีทั่วไป:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. หากคุณต้องการใช้ไวยากรณ์คุณสมบัติ
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. หากคุณประกาศประเภทฟังก์ชั่นก่อนแล้ว
type MyFnType = (arg1: number, arg2: number) => number;

export interface IParam {
  title: string;
  callback: MyFnType;
}

การใช้ตรงไปตรงมามาก

function callingFn(paramInfo: IParam):number {
    let needToCall = true;
    let result = 0;
   if(needToCall){
     result = paramInfo.callback(1,2);
    }

    return result;
}
  1. คุณสามารถประกาศประเภทฟังก์ชันตามตัวอักษรได้เช่นกันซึ่งหมายความว่าฟังก์ชั่นสามารถรับฟังก์ชั่นอื่นได้เนื่องจากเป็นพารามิเตอร์ ฟังก์ชั่น parameterize สามารถเรียกว่าเป็นการโทรกลับยัง
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

10

มีฟังก์ชั่นนามธรรมสี่ประเภทคุณสามารถใช้มันแยกกันเมื่อคุณรู้ว่าฟังก์ชั่นของคุณจะรับอาร์กิวเมนต์หรือไม่จะส่งคืนข้อมูลหรือไม่

export declare type fEmptyVoid = () => void;
export declare type fEmptyReturn = () => any;
export declare type fArgVoid = (...args: any[]) => void;
export declare type fArgReturn = (...args: any[]) => any;

แบบนี้:

public isValid: fEmptyReturn = (): boolean => true;
public setStatus: fArgVoid = (status: boolean): void => this.status = status;

สำหรับการใช้งานเพียงประเภทเดียวประเภทฟังก์ชั่นใด ๆ เราสามารถรวมประเภทนามธรรมทั้งหมดเข้าด้วยกันเช่นนี้

export declare type fFunction = fEmptyVoid | fEmptyReturn | fArgVoid | fArgReturn;

จากนั้นใช้มันเหมือน:

public isValid: fFunction = (): boolean => true;
public setStatus: fFunction = (status: boolean): void => this.status = status;

ในตัวอย่างข้างต้นทุกอย่างถูกต้อง แต่ตัวอย่างการใช้งานในการร้องไม่ถูกต้องจากมุมมองของโปรแกรมแก้ไขโค้ดส่วนใหญ่

// you can call this function with any type of function as argument
public callArgument(callback: fFunction) {

    // but you will get editor error if call callback argument like this
    callback();
}

การเรียกบรรณาธิการที่ถูกต้องเป็นเช่นนี้:

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}

2

typescript: วิธีกำหนดประเภทสำหรับการเรียกฟังก์ชันที่ใช้ในพารามิเตอร์method

คุณสามารถประกาศการเรียกกลับเป็น 1) คุณสมบัติของฟังก์ชั่นหรือ 2) วิธีการ :

interface ParamFnProp {
    callback: (a: Animal) => void; // function property
}

interface ParamMethod {
    callback(a: Animal): void; // method
}

มีความแตกต่างที่สำคัญในการพิมพ์ตั้งแต่TS 2.6 :

คุณได้รับชนิด ("เสียง") ที่แข็งแกร่งขึ้นใน--strictหรือ--strictFunctionTypesโหมดเมื่อมีการประกาศคุณสมบัติของฟังก์ชัน ลองมาตัวอย่าง:

const animalCallback = (a: Animal): void => { } // Animal is the base type for Dog
const dogCallback = (d: Dog): void => { } 
// function property variant
const param11: ParamFnProp = { callback: dogCallback } // error: not assignable
const param12: ParamFnProp = { callback: animalCallback } // works

// method variant
const param2: ParamMethod = { callback: dogCallback } // now it works again ...

เทคนิคการพูดวิธีการมีbivariantและคุณสมบัติฟังก์ชั่นcontravariantstrictFunctionTypesในการขัดแย้งของพวกเขาภายใต้ วิธีการยังคงมีการตรวจสอบมากขึ้น permissively (แม้ว่าจะไม่ได้เสียง) Arrayจะเป็นบิตการปฏิบัติมากขึ้นในการรวมกันกับในตัวชนิดเช่น

สรุป

  • มีความแตกต่างระหว่างคุณสมบัติของฟังก์ชันและการประกาศเมธอด
  • เลือกคุณสมบัติฟังก์ชั่นสำหรับประเภทที่แข็งแกร่งกว่าถ้าเป็นไปได้

รหัสตัวอย่างสนามเด็กเล่น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.