Typescript: come definire il tipo per un callback di funzione (come qualsiasi tipo di funzione, non universale) usato in un parametro di metodo


313

Attualmente ho la definizione del tipo come:

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

Ho bisogno di qualcosa del tipo:

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

ma il secondo non viene accettato.

Risposte:


285

Il tipo globale Functionserve a questo scopo.

Inoltre, se si intende richiamare questo callback con 0 argomenti e si ignora il valore restituito, il tipo () => voidcorrisponde a tutte le funzioni che non accettano argomenti.


27
questa cosa manca nei tipi base
Yogesh,

13
Non è un tipo di base perché dovresti definire i tuoi argomenti e restituire i valori. qualcosa come callback: (numero: numero) => void; è molto più utile per il controllo del tipo di callback: function; sarebbe.
kpup,

@kpup Per essere chiari, stai dicendo di non usare la maiuscola F Functioncome mostrato nella prima riga di questa risposta, e dici che il secondo paragrafo (usando il tipo di () => voido qualunque cosa corrisponda al caso d'uso) è preferito?
ruffin,

2
FWIW, i documenti sui tipi di funzione sono disponibili qui
imjared

191

Typescript da v1.4 ha la typeparola chiave che dichiara un alias di tipo (analogo a a typedefin C / C ++). Puoi dichiarare il tuo tipo di callback così:

type CallbackFunction = () => void;

che dichiara una funzione che non accetta argomenti e non restituisce nulla. Una funzione che accetta zero o più argomenti di qualsiasi tipo e non restituisce nulla sarebbe:

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

Quindi puoi dire, ad esempio,

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

Se si desidera una funzione che accetta un numero arbitrario di argomenti e restituisce qualsiasi cosa (incluso vuoto):

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

È possibile specificare alcuni argomenti obbligatori e quindi una serie di argomenti aggiuntivi (ad esempio una stringa, un numero e quindi una serie di argomenti aggiuntivi) in questo modo:

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

Questo può essere utile per cose come i gestori EventEmitter.

In questo modo le funzioni possono essere digitate quanto più ti piace, sebbene tu possa lasciarti trasportare e incorrere in problemi combinatori se provi a inchiodare tutto con un alias di tipo.


1
Tra Functione (...args: any[]) => anycosa è preferito?
circa il

@ahong: Personalmente preferirei quest'ultima in quanto fornisce una firma ... normalmente. ...args: any[]non è molto utile.
Ed S.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;quello che stavo cercando, ty.
aqteifan,

61

A seguito della risposta di Ryan, penso che l'interfaccia che stai cercando sia definita come segue:

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

34

Ecco un esempio di una funzione che accetta un callback

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

Se non ti interessano i valori di ritorno dei callback (la maggior parte delle persone non sa come utilizzarli in modo efficace), puoi utilizzare 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
});

Nota, la firma che ho usato per il callbackparametro ...

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

Direi che si tratta di un difetto di TypeScript perché ci si aspetta che fornisca un nome per i parametri di callback. In questo caso l'ho usato _perché non è utilizzabile all'interno disqk funzione.

Tuttavia, se lo fai

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

È TypeScript valido , ma verrà interpretato come ...

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

Vale a dire, TypeScript penserà che il nome del parametro sia numbere il tipo implicito siaany . Ovviamente non è quello che intendevamo, ma purtroppo è così che funziona TypeScript.

Quindi non dimenticare di fornire i nomi dei parametri durante la digitazione dei parametri della funzione ... stupido come potrebbe sembrare.


32

È possibile definire un tipo di funzione nell'interfaccia in vari modi,

  1. modo generale:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Se desideri utilizzare la sintassi delle proprietà,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Se si dichiara prima il tipo di funzione,
type MyFnType = (arg1: number, arg2: number) => number;

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

L'uso è molto semplice,

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

    return result;
}
  1. È possibile dichiarare anche un tipo di funzione letterale, il che significa che una funzione può accettare un'altra funzione come parametro. la funzione parametrizza può essere chiamata anche come callback.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

10

Esistono quattro tipi di funzioni astratte, puoi usarle separatamente quando sai che la tua funzione prenderà un argomento o meno, restituirà un dato o meno.

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

come questo:

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

Per utilizzare un solo tipo come qualsiasi tipo di funzione, possiamo combinare tutti i tipi astratti insieme, in questo modo:

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

quindi usalo come:

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

Nell'esempio sopra tutto è corretto. Ma l'esempio di utilizzo in basso non è corretto dal punto di vista della maggior parte degli editor di codice.

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

La chiamata corretta per i redattori è così:

public callArgument(callback: fFunction) {

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

2

Dattiloscritto: come definire il tipo per un callback di funzione utilizzato in un parametro di metodo ?

È possibile dichiarare il callback come 1) proprietà della funzione o 2) metodo :

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

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

Esiste un'importante differenza di battitura rispetto a TS 2.6 :

Si ottengono tipi più forti ("audio") in --stricto --strictFunctionTypesmode, quando viene dichiarata una proprietà di funzione . Facciamo un esempio:

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

Tecnicamente parlato, i metodi sono bivariant e le proprietà funzionali contravariant nei loro argomenti sotto strictFunctionTypes. I metodi sono ancora controllati in modo più permissivo (anche se non sano) per essere un po 'più pratico in combinazione con tipi integrati comeArray .

Sommario

  • Esiste una differenza di tipo tra la proprietà della funzione e la dichiarazione del metodo
  • Scegli una proprietà di funzione per tipi più forti, se possibile

Codice di esempio del parco giochi

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.