Typescript: Як визначити тип для зворотного виклику функції (як будь-якого типу функції, не універсального), який використовується в параметрі методу


313

В даний час у мене є визначення типу:

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

Мені потрібно щось на кшталт:

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

але 2-го не приймається.

Відповіді:


285

Глобальному типу Functionслужить цій цілі.

Крім того, якщо ви маєте намір викликати цей зворотний дзвінок з 0 аргументами і буде ігнорувати його повернене значення, тип () => voidвідповідає всім функціям без аргументів.


27
ця річ відсутня в основних типах
Йогеш

13
Це не основний тип, тому що ви повинні визначити свої аргументи та повернути значення. щось на зразок зворотного виклику: (число: номер) => недійсний; набагато корисніше для перевірки типу, ніж зворотний виклик: функція; було б.
kpup

@kpup Щоб бути зрозумілим, ви хочете сказати, що не використовувати прописний F, Functionяк показано в першому рядку цієї відповіді, і говорити, що другий абзац (використовуючи тип () => voidабо що відповідає випадку використання) є кращим?
ruffin

2
FWIW, документи про типи функцій доступні тут
відмінено

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.

Функції можна вводити настільки сильно, як вам подобається таким чином, хоча ви можете захопитися і зіткнутися з комбінаторними проблемами, якщо спробуєте забити все внизу псевдонімом типу.


1
Між чим Functionі (...args: any[]) => anyщо перевагу?
Ahong

@ahong: Особисто я віддаю перевагу останньому, оскільки він надає підпис ... як правило. ...args: any[]не дуже корисно.
Ред С.

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. Ви також можете оголосити тип функції буквальним, що означає, що функція може приймати іншу функцію як її параметр. функцію параметризації можна також викликати як зворотний дзвінок.
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: Як визначити тип для зворотного виклику функції, який використовується в параметрі методу ?

Ви можете оголосити зворотний виклик як 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 ...

З технічної точки зору , методи є двоваріантними та функціональними властивостями, суперечливими у своїх аргументах під strictFunctionTypes. Методи все-таки перевіряються більш дозвільно (навіть якщо вони не звучать), щоб бути трохи практичнішими в поєднанні з вбудованими типами типу Array.

Підсумок

  • Існує різниця типів між властивістю функції та оголошенням методу
  • Виберіть властивість функції для більш сильних типів, якщо це можливо

Зразок коду дитячої площадки

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.