Mecanografiado: cómo definir el tipo para una devolución de llamada de función (como cualquier tipo de función, no universal) utilizada en un parámetro de método


313

Actualmente tengo la definición de tipo como:

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

Necesito algo como:

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

pero el segundo no está siendo aceptado.

Respuestas:


285

El tipo global Functionsirve para este propósito.

Además, si tiene la intención de invocar esta devolución de llamada con 0 argumentos e ignorará su valor de retorno, el tipo () => voidcoincide con todas las funciones sin tomar argumentos.


27
esto falta en los tipos básicos
Yogesh

13
No es un tipo básico porque debe definir sus argumentos y valores de retorno. algo así como devolución de llamada: (número: número) => nulo; es mucho más útil para la verificación de tipos que la devolución de llamada: función; sería.
kpup

@kpup Para ser claros, ¿está diciendo que no use F mayúscula Functioncomo se muestra en la primera línea de esta respuesta, y dice que () => voidse prefiere el segundo párrafo (usando el tipo de o lo que coincida con el caso de uso)?
ruffin

2
FWIW, los documentos sobre los tipos de funciones están disponibles aquí
publicado el

191

El mecanografiado de v1.4 tiene la typepalabra clave que declara un alias de tipo (análogo a a typedefen C / C ++). Puede declarar su tipo de devolución de llamada así:

type CallbackFunction = () => void;

que declara una función que no toma argumentos y no devuelve nada. Una función que toma cero o más argumentos de cualquier tipo y no devuelve nada sería:

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

Entonces puedes decir, por ejemplo,

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

Si desea una función que tome un número arbitrario de argumentos y devuelva cualquier cosa (incluido void)

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

Puede especificar algunos argumentos obligatorios y luego un conjunto de argumentos adicionales (digamos una cadena, un número y luego un conjunto de argumentos adicionales) así:

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

Esto puede ser útil para cosas como los controladores EventEmitter.

Las funciones se pueden escribir tan fuertemente como desee de esta manera, aunque puede dejarse llevar y tener problemas combinatorios si trata de precisar todo con un alias de tipo.


1
¿Entre Functiony (...args: any[]) => anyqué se prefiere?
ahong

@ahong: Personalmente, preferiría este último ya que proporciona una firma ... normalmente. ...args: any[]No es muy útil.
Ed S.

type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;Lo que estaba buscando, Ty.
aqteifan

61

Siguiendo la respuesta de Ryan, creo que la interfaz que está buscando se define de la siguiente manera:

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

34

Aquí hay un ejemplo de una función que acepta una devolución de llamada

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 no le importan los valores de retorno de las devoluciones de llamada (la mayoría de las personas no saben cómo utilizarlas de manera efectiva), puede usar 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
});

Tenga en cuenta que la firma que utilicé para el callbackparámetro ...

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

Yo diría que esto es una deficiencia de TypeScript porque se espera que proporcionemos un nombre para los parámetros de devolución de llamada. En este caso lo usé _porque no se puede usar dentro de la sqkfunción.

Sin embargo, si haces esto

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

Es TypeScript válido , pero se interpretará como ...

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

Es decir, TypeScript pensará que el nombre del parámetro es numbery el tipo implícito es any. Obviamente, esto no es lo que pretendíamos, pero, por desgracia, así es como funciona TypeScript.

Así que no olvides proporcionar los nombres de los parámetros al escribir los parámetros de tu función ... por estúpido que parezca.


32

Puede definir un tipo de función en la interfaz de varias maneras,

  1. forma general:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Si desea utilizar la sintaxis de propiedad, entonces,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Si declara el tipo de función primero, entonces,
type MyFnType = (arg1: number, arg2: number) => number;

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

Usar es muy sencillo,

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

    return result;
}
  1. También puede declarar un tipo de función literal, lo que significa que una función puede aceptar otra función como parámetro. La función de parametrización también se puede llamar como devolución de llamada.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

10

Hay cuatro tipos de funciones abstractas, puede usarlas por separado cuando sepa que su función tomará un argumento o no, devolverá un dato o no.

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

Me gusta esto:

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

Para usar solo un tipo como cualquier tipo de función, podemos combinar todos los tipos abstractos juntos, así:

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

luego úsalo como:

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

En el ejemplo anterior, todo es correcto. Pero el ejemplo de uso a continuación no es correcto desde el punto de vista de la mayoría de los editores de código.

// 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 llamada correcta para los editores es así:

public callArgument(callback: fFunction) {

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

2

Mecanografiado: ¿Cómo definir el tipo para una devolución de llamada de función utilizada en un parámetro de método ?

Puede declarar la devolución de llamada como 1) propiedad de función o 2) método :

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

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

Hay una diferencia de tipeo importante desde TS 2.6 :

Obtiene tipos más fuertes ("sonido") en --stricto --strictFunctionTypesmodo, cuando se declara una propiedad de función . Tomemos un ejemplo:

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

Técnicamente hablando, los métodos son bivariantes y las propiedades de la función son contravariantes en sus argumentos bajo strictFunctionTypes. Los métodos aún se verifican de manera más permisiva (incluso si no suena) para que sean un poco más prácticos en combinación con tipos incorporados como Array.

Resumen

  • Hay una diferencia de tipo entre la propiedad de la función y la declaración del método
  • Elija una propiedad de función para tipos más fuertes, si es posible

Código de muestra del patio de recreo

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.