Type de script: comment définir le type d'un rappel de fonction (comme n'importe quel type de fonction, pas universel) utilisé dans un paramètre de méthode

313

Actuellement, j'ai une définition de type comme:

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

J'ai besoin de quelque chose comme:

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

mais le 2ème n'est pas accepté.

Smrutiranjan Sahu
la source

Réponses:

285

Le type global Functionsert cet objectif.

En outre, si vous avez l'intention d'appeler ce rappel avec 0 arguments et que vous ignorerez sa valeur de retour, le type () => voidcorrespond à toutes les fonctions ne prenant aucun argument.

Ryan Cavanaugh
la source
27
cette chose manque dans les types de base
Yogesh
13
Ce n'est pas un type de base car vous devez définir vos arguments et renvoyer des valeurs. quelque chose comme rappel: (nombre: numéro) => vide; est beaucoup plus utile pour la vérification de type que callback: function; serait.
kpup
@kpup Pour être clair, dites-vous de ne pas utiliser le F majuscule Functioncomme indiqué dans la première ligne de cette réponse, et dites-vous que le deuxième paragraphe (en utilisant le type de () => voidou ce qui correspond au cas d'utilisation) est préféré?
ruffin
2
FWIW, des documents sur les types de fonctions sont disponibles ici
imjared
191

Typescript de v1.4 a le typemot - clé qui déclare un alias de type (analogue à un typedefen C / C ++). Vous pouvez déclarer votre type de rappel ainsi:

type CallbackFunction = () => void;

qui déclare une fonction qui ne prend aucun argument et ne renvoie rien. Une fonction qui prend zéro ou plusieurs arguments de tout type et ne renvoie rien serait:

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

Ensuite, vous pouvez dire, par exemple,

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

Si vous voulez une fonction qui accepte un nombre arbitraire d'arguments et renvoie n'importe quoi (y compris void):

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

Vous pouvez spécifier des arguments obligatoires puis un ensemble d'arguments supplémentaires (disons une chaîne, un nombre puis un ensemble d'arguments supplémentaires) ainsi:

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

Cela peut être utile pour des choses comme les gestionnaires EventEmitter.

Les fonctions peuvent être saisies aussi fortement que vous le souhaitez de cette façon, bien que vous puissiez vous laisser emporter et rencontrer des problèmes combinatoires si vous essayez de tout clouer avec un alias de type.

David G
la source
1
Entre Functionet (...args: any[]) => anyqu'est-ce qui est préféré?
ahong
@ahong: Personnellement, je préférerais ce dernier car il fournit une signature ... normalement. ...args: any[]n'est pas très utile.
Ed S.
type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;ce que je cherchais, ty.
aqteifan
61

À la suite de la réponse de Ryan, je pense que l'interface que vous recherchez est définie comme suit:

interface Param {
    title: string;
    callback: () => void;
}
poisson bleu
la source
34

Voici un exemple de fonction qui accepte un rappel

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

Si vous ne vous souciez pas des valeurs de retour des rappels (la plupart des gens ne savent pas comment les utiliser de manière efficace), vous pouvez utiliser 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
});

Remarque, la signature que j'ai utilisée pour le callbackparamètre ...

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

Je dirais que c'est une déficience TypeScript car nous sommes censés fournir un nom pour les paramètres de rappel. Dans ce cas, j'ai utilisé _car il n'est pas utilisable à l'intérieur dusqk fonction.

Cependant, si vous faites cela

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

Ses TypeScript valide , mais il sera interprété comme ...

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

C'est-à-dire que TypeScript pensera que le paramètre nom est numberet le type implicite l'est any. Ce n'est évidemment pas ce que nous voulions, mais hélas, c'est ainsi que TypeScript fonctionne.

N'oubliez donc pas de fournir les noms des paramètres lors de la saisie des paramètres de votre fonction ... aussi stupide que cela puisse paraître.

Je vous remercie
la source
32

Vous pouvez définir un type de fonction dans l'interface de différentes manières,

  1. manière générale:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Si vous souhaitez utiliser la syntaxe des propriétés,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Si vous déclarez d'abord le type de fonction,
type MyFnType = (arg1: number, arg2: number) => number;

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

L'utilisation est très simple,

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

    return result;
}
  1. Vous pouvez également déclarer un type de fonction littéral, ce qui signifie qu'une fonction peut accepter une autre fonction comme paramètre. La fonction de paramétrage peut également être appelée comme rappel.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}
Humayoun_Kabir
la source
10

Il existe quatre types de fonctions abstraites, vous pouvez les utiliser séparément lorsque vous savez que votre fonction prendra ou non un argument, retournera des données ou non.

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

comme ça:

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

Pour utiliser un seul type comme n'importe quel type de fonction, nous pouvons combiner tous les types abstraits, comme ceci:

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

puis utilisez-le comme:

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

Dans l'exemple ci-dessus, tout est correct. Mais l'exemple d'utilisation ci-dessous n'est pas correct du point de vue de la plupart des éditeurs de code.

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

Un appel correct aux éditeurs est le suivant:

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}
Artur T
la source
2

Typographie: Comment définir le type d'un rappel de fonction utilisé dans un paramètre de méthode ?

Vous pouvez déclarer le rappel comme 1) propriété de fonction ou 2) méthode :

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

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

Il existe une différence de frappe importante depuis TS 2.6 :

Vous obtenez des types plus forts ("son") en mode --strictou --strictFunctionTypes, lorsqu'une propriété de fonction est déclarée. Prenons un exemple:

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

Techniquement parlant, les méthodes sont bivariantes et les propriétés des fonctions contravariantes dans leurs arguments ci-dessous strictFunctionTypes. Les méthodes sont toujours vérifiées de manière plus permissive (même si elles ne sont pas saines) pour être un peu plus pratiques en combinaison avec des types intégrés commeArray .

Résumé

  • Il existe une différence de type entre la propriété de fonction et la déclaration de méthode
  • Choisissez une propriété de fonction pour les types plus forts, si possible

Exemple de code Playground

ford04
la source