Typescript: Jak zdefiniować typ dla wywołania zwrotnego funkcji (jako dowolny typ funkcji, nie uniwersalny) używany w parametrze metody


313

Obecnie mam definicję typu jako:

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

Potrzebuję czegoś takiego:

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

ale druga nie jest akceptowana.

Odpowiedzi:


285

Typ globalny Functionsłuży temu celowi.

Dodatkowo, jeśli zamierzasz wywołać to wywołanie zwrotne z 0 argumentami i zignorujesz jego wartość zwracaną, typ () => voidpasuje do wszystkich funkcji bez argumentów.


27
tego brakuje w podstawowych typach
Yogesh

13
Nie jest to typ podstawowy, ponieważ należy zdefiniować argumenty i zwrócić wartości. coś takiego jak callback: (number: number) => void; jest znacznie bardziej przydatny do sprawdzania typu niż callback: funkcja; byłoby.
kpup

@kpup Mówiąc jasno, czy mówisz, aby nie używać dużej litery F, Functionjak pokazano w pierwszym wierszu tej odpowiedzi, i mówiąc, że () => voidpreferowany jest akapit drugi (z użyciem typu lub cokolwiek pasującego do przypadku użycia)?
ruffin

2
FWIW, dokumenty na temat typów funkcji są dostępne tutaj
imjared

191

Maszynopis z wersji 1.4 zawiera typesłowo kluczowe, które deklaruje alias typu (analogicznie jak typedefw C / C ++). Możesz zadeklarować swój typ wywołania zwrotnego w ten sposób:

type CallbackFunction = () => void;

która deklaruje funkcję, która nie przyjmuje argumentów i nic nie zwraca. Funkcja, która pobiera zero lub więcej argumentów dowolnego typu i nic nie zwraca:

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

Możesz na przykład powiedzieć

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

Jeśli potrzebujesz funkcji, która pobiera dowolną liczbę argumentów i zwraca cokolwiek (w tym void):

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

Możesz podać niektóre obowiązkowe argumenty, a następnie zestaw dodatkowych argumentów (np. Ciąg, liczbę, a następnie zestaw dodatkowych argumentów) w ten sposób:

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

Może to być przydatne w przypadku programów obsługi EventEmitter.

W ten sposób można wpisywać funkcje tak mocno, jak chcesz, chociaż możesz dać się ponieść emocjom i napotkać problemy kombinatoryczne, jeśli spróbujesz dopiąć wszystko za pomocą aliasu typu.


1
Pomiędzy Functioni (...args: any[]) => anyco jest preferowane?
ahong

@ahong: Osobiście wolałbym ten drugi, ponieważ zapewnia on podpis ... normalnie. ...args: any[]nie jest bardzo przydatne.
Ed S.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;czego szukałem ty.
aqteifan

61

Po odpowiedzi Ryana myślę, że interfejs, którego szukasz, został zdefiniowany w następujący sposób:

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

34

Oto przykład funkcji, która akceptuje wywołanie zwrotne

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

Jeśli nie zależy Ci na wartościach zwrotnych wywołań zwrotnych (większość ludzi nie wie, jak je wykorzystać w jakikolwiek skuteczny sposób), możesz użyć 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
});

Uwaga: podpis użyłem dla callbackparametru ...

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

Powiedziałbym, że jest to niedobór TypeScript, ponieważ oczekuje się, że podamy nazwę parametrów wywołania zwrotnego. W tym przypadku użyłem, _ponieważ nie można go użyć w sqkfunkcji.

Jeśli jednak to zrobisz

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

Jest poprawny TypeScript, ale będzie interpretowany jako ...

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

Tzn. TypeScript pomyśli, że nazwa parametru to numberi domyślny typ to any. Oczywiście nie to zamierzaliśmy, ale niestety, tak działa TypeScript.

Więc nie zapomnij podać nazw parametrów podczas wpisywania parametrów funkcji ... głupio, jak mogłoby się wydawać.


32

Możesz zdefiniować typ funkcji w interfejsie na różne sposoby,

  1. ogólny sposób:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Jeśli chcesz użyć składni właściwości,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Jeśli najpierw zadeklarujesz typ funkcji,
type MyFnType = (arg1: number, arg2: number) => number;

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

Korzystanie jest bardzo proste,

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

    return result;
}
  1. Możesz także zadeklarować literał typu funkcji, co oznacza, że ​​funkcja może zaakceptować inną funkcję jako parametr. Funkcja parametryzacji może być również wywoływana jako wywołanie zwrotne.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

10

Istnieją cztery abstrakcyjne typy funkcji, których można używać osobno, gdy wiadomo, że funkcja pobierze argument (y) lub nie, zwróci dane lub nie.

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

lubię to:

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

Aby użyć tylko jednego typu jako dowolnego typu funkcji, możemy połączyć wszystkie typy abstrakcyjne razem, tak jak to:

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

następnie użyj go w następujący sposób:

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

W powyższym przykładzie wszystko jest poprawne. Jednak poniższy przykład użycia jest niepoprawny z punktu widzenia większości edytorów kodu.

// 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();
}

Prawidłowe połączenie dla redaktorów wygląda następująco:

public callArgument(callback: fFunction) {

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

2

Typescript: Jak zdefiniować typ wywołania zwrotnego funkcji używanego w parametrze metody ?

Możesz zadeklarować wywołanie zwrotne jako 1) właściwość funkcji lub 2) metodę :

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

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

Istnieje istotna różnica w pisaniu od TS 2.6 :

Otrzymujesz silniejsze („dźwiękowe”) typy w trybie --strictlub --strictFunctionTypes, gdy deklarowana jest właściwość funkcji . Weźmy przykład:

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 ...

Technicznie mówiony, metody są bivariant i właściwości funkcyjne kontrawariantny w swoich argumentach poniżej strictFunctionTypes. Metody są nadal sprawdzane w sposób bardziej dozwolony (nawet jeśli nie dźwiękowy), aby były nieco bardziej praktyczne w połączeniu z typami wbudowanymi, takimi jak Array.

Podsumowanie

  • Istnieje różnica typu między właściwością funkcji a deklaracją metody
  • Jeśli to możliwe, wybierz właściwość funkcji dla silniejszych typów

Przykładowy kod placu zabaw

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.