Datilografado: como definir o tipo para um retorno de chamada de função (como qualquer tipo de função, não universal) usado em um parâmetro de método

313

Atualmente, tenho definição de tipo como:

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

Eu preciso de algo como:

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

mas o segundo não está sendo aceito.

Smrutiranjan Sahu
fonte

Respostas:

285

O tipo global Functionserve a esse propósito.

Além disso, se você pretende invocar esse retorno de chamada com 0 argumentos e ignorará seu valor de retorno, o tipo () => voidcorresponderá a todas as funções sem argumentos.

Ryan Cavanaugh
fonte
27
esta coisa está faltando em tipos básicos
Yogesh
13
Não é um tipo básico, porque você deve definir seus argumentos e retornar valores. algo como retorno de chamada: (número: número) => nulo; é muito mais útil para verificação de tipo do que callback: function; seria.
KPUP
@kpup Para ficar claro, você está dizendo para não usar o capital F, Functioncomo mostrado na primeira linha desta resposta, e dizendo que o segundo parágrafo (usando o tipo de () => voidou o que corresponde ao caso de uso) é o preferido?
Ruffin
2
FWIW, documentos sobre tipos de funções estão disponíveis aqui
imjared
191

Texto typedatilografado da v1.4 possui a palavra - chave que declara um alias de tipo (análogo a um typedefem C / C ++). Você pode declarar seu tipo de retorno de chamada assim:

type CallbackFunction = () => void;

que declara uma função que não aceita argumentos e não retorna nada. Uma função que recebe zero ou mais argumentos de qualquer tipo e não retorna nada seria:

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

Então você pode dizer, por exemplo,

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

Se você deseja uma função que recebe um número arbitrário de argumentos e retorna qualquer coisa (incluindo nulo):

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

Você pode especificar alguns argumentos obrigatórios e, em seguida, um conjunto de argumentos adicionais (por exemplo, uma string, um número e, em seguida, um conjunto de argumentos adicionais) assim:

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

Isso pode ser útil para coisas como manipuladores de EventEmitter.

As funções podem ser digitadas com a mesma força que você desejar dessa maneira, embora você possa se deixar levar e ter problemas combinatórios se tentar definir tudo com um alias de tipo.

David G
fonte
1
Entre Functione o (...args: any[]) => anyque é preferido?
ahong
@ahong: Pessoalmente, eu prefiro o último, pois fornece uma assinatura ... normalmente. ...args: any[]não é muito útil.
21419 Ed Ed
type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void;o que eu estava procurando, ty.
aqteifan
61

Seguindo a resposta de Ryan, acho que a interface que você está procurando é definida da seguinte maneira:

interface Param {
    title: string;
    callback: () => void;
}
peixe branco
fonte
34

Aqui está um exemplo de uma função que aceita um retorno de chamada

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 você não se importa com os valores de retorno dos retornos de chamada (a maioria das pessoas não sabe como utilizá-los de maneira eficaz), você pode 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
});

Observe que a assinatura que usei para o callbackparâmetro ...

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

Eu diria que isso é uma deficiência do TypeScript, porque é esperado que forneçamos um nome para os parâmetros de retorno de chamada. Nesse caso, usei _porque não é utilizável dentro dosqk função.

No entanto, se você fizer isso

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

É válido TypeScript, mas será interpretado como ...

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

Ou seja, o TypeScript pensará que o nome do parâmetro é numbere o tipo implícito é any. Obviamente, não é isso que pretendemos, mas, infelizmente, é assim que o TypeScript funciona.

Portanto, não se esqueça de fornecer os nomes dos parâmetros ao digitar os parâmetros de sua função ... por mais estúpido que possa parecer.

Obrigado
fonte
32

Você pode definir um tipo de função na interface de várias maneiras,

  1. maneira geral:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. Se você deseja usar a sintaxe da propriedade,
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. Se você declarar o tipo de função primeiro,
type MyFnType = (arg1: number, arg2: number) => number;

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

Usando é muito simples,

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

    return result;
}
  1. Você também pode declarar um tipo de função literal, o que significa que uma função pode aceitar outra função como parâmetro. A função parametrizada também pode ser chamada como retorno de chamada.
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}
Humayoun_Kabir
fonte
10

Existem quatro tipos de funções abstratas, você pode usá-los separadamente quando souber que sua função terá argumentos ou não, retornará dados ou não.

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

como isso:

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

Para usar apenas um tipo como qualquer tipo de função, podemos combinar todos os tipos abstratos, assim:

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

então use-o como:

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

No exemplo acima, tudo está correto. Mas o exemplo de uso abaixo não está correto do ponto de vista da maioria dos 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();
}

A chamada correta para editores é assim:

public callArgument(callback: fFunction) {

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

Texto datilografado: como definir o tipo para um retorno de chamada de função usado em um parâmetro de método ?

Você pode declarar o retorno de chamada como 1) propriedade da função ou 2) método :

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

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

Há uma diferença de digitação importante desde o TS 2.6 :

Você obtém tipos mais fortes ("som") no modo --strictou --strictFunctionTypes, quando uma propriedade de função é declarada. Vamos dar um exemplo:

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 falado, os métodos são bivariada e propriedades funcionais contravariante em seus argumentos sob strictFunctionTypes. Os métodos ainda são verificados de forma mais permissiva (mesmo que não sejam sonoros) para serem um pouco mais práticos em combinação com tipos internos, como Array.

Resumo

  • Há uma diferença de tipo entre a propriedade da função e a declaração do método
  • Escolha uma propriedade de função para tipos mais fortes, se possível

Código de exemplo do parque infantil

ford04
fonte