ChatGPT解决这个技术问题 Extra ChatGPT

How to define type for a function callback (as any function type, not universal any) used in a method parameter

Currently I have type definition as:

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

I need something like:

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

but the 2nd one is not being accepted.

it's upper case callback:Function instead of lower case callback:function
I found out Function wasn't compatible is one case so I created an "AnyFunction" type: export type AnyFunction = (...args: any[]) => any;

R
Ryan Cavanaugh

The global type Function serves this purpose.

Additionally, if you intend to invoke this callback with 0 arguments and will ignore its return value, the type () => void matches all functions taking no arguments.


this thing is missing in basic types
It's not a basic type because you should define your arguments and return values. something like callback: (number: number) => void; is much more useful for type checking than callback: function; would be.
FWIW, docs on function types are available here
@SgtPooki Given that Ryan is the lead of the Typescript team and your edits are very significant, are you sure they belong more as edits rather than as your own answer? I think your additions are valid advice but given Ryan's authority I'm surprised to find your edits here, particularly where they contradict or change the meaning of the original post.
Note that ESLint gives some advice against using Function as a type directly -- quote "Don't use Function as a type. The Function type accepts any function-like value. It provides no type safety when calling the function, which can be a common source of bugs. It also accepts things like class declarations, which will throw at runtime as they will not be called with new."
D
David G

Typescript from v1.4 has the type keyword which declares a type alias (analogous to a typedef in C/C++). You can declare your callback type thus:

type CallbackFunction = () => void;

which declares a function that takes no arguments and returns nothing. A function that takes zero or more arguments of any type and returns nothing would be:

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

Then you can say, for example,

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

If you want a function that takes an arbitrary number of arguments and returns anything (including void):

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

You can specify some mandatory arguments and then a set of additional arguments (say a string, a number and then a set of extra args) thus:

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

This can be useful for things like EventEmitter handlers.

Functions can be typed as strongly as you like in this fashion, although you can get carried away and run into combinatoric problems if you try to nail everything down with a type alias.


Between Function and (...args: any[]) => any what is preferred?
@ahong: Personally I would prefer the latter as it provides a signature... normally. ...args: any[] isn't very useful.
type CallbackFunctionSomeVariadic = (arg1: string, arg2: number, ...args: any[]) => void; what i was looking for, ty.
Seems I was able to export and reuse a definition in other components like this export type CallbackFunctionSomething = (page: number, sort: blablabla) => void
I found out an interesting thing: Function is NOT the same as (...args: any[]) => any
b
blorkfish

Following from Ryan's answer, I think that the interface you are looking for is defined as follows:

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

H
Humayoun_Kabir

You can define a function type in interface in various ways,

general way:

export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}

If you would like to use property syntax then,

export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}

If you declare the function type first then,

type MyFnType = (arg1: number, arg2: number) => number;

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

Using is very straight forward,

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

    return result;
}

You can declare a function type literal also , which mean a function can accept another function as it's parameter. parameterize function can be called as callback also.

export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

this is what I wanted.
M
Mulan

Here's an example of a function that accepts a 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
});

If you don't care about the return values of callbacks (most people don't know how to utilize them in any effective way), you can use 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
});

Note, the signature I used for the callback parameter ...

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

I would say this is a TypeScript deficiency because we are expected to provide a name for the callback parameters. In this case I used _ because it's not usable inside the sqk function.

However, if you do this

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

It's valid TypeScript, but it will interpreted as ...

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

Ie, TypeScript will think the parameter name is number and the implied type is any. This is obviously not what we intended, but alas, that is how TypeScript works.

So don't forget to provide the parameter names when typing your function parameters... stupid as it might seem.


A
Artur T

There are four abstract function types, you can use them separately when you know your function will take an argument(s) or not, will return a data or not.

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

like this:

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

For use only one type as any function type we can combine all abstract types together, like this:

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

then use it like:

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

In the example above everything is correct. But the usage example in bellow is not correct from the point of view of most code editors.

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

Correct call for editors is like this:

public callArgument(callback: fFunction) {

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

D
Ders

Note that the TypeScript ESLint plugin has recommended rules ban-types (error) and no-explicit-any (warn).

Avoid the Function type, as it provides little safety

In compliance with these rules, maybe the best solution is,

callback: (...args: unknown[]) => unknown

C
Community

Typescript: How to define type for a function callback used in a method parameter?

You can declare the callback as 1) function property or 2) method:

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

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

There is an important typing difference since TS 2.6:

You get stronger ("sound") types in --strict or --strictFunctionTypes mode, when a function property is declared. Let's take an example:

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

Technically spoken, methods are bivariant and function properties contravariant in their arguments under strictFunctionTypes. Methods are still checked more permissively (even if not sound) to be a bit more practical in combination with built-in types like Array.

Summary

There is a type difference between function property and method declaration

Choose a function property for stronger types, if possible

Playground sample code


r
rksh1997

Hopefully, this will help...

interface Param {
    title: string;
    callback: (error: Error, data: string) => void;
}

Or in a Function


let myfunction = (title: string, callback: (error: Error, data: string) => void): string => {

    callback(new Error(`Error Message Here.`), "This is callback data.");
    return title;

}


E
Edwin Pratt

I've just started using Typescript and I've been trying to solve a similar problem like this; how to tell the Typescript that I'm passing a callback without an interface.

After browsing a few answers on Stack Overflow and GitHub issues, I finally found a solution that may help anyone with the same problem.

A function's type can be defined with (arg0: type0) => returnType and we can use this type definition in another function's parameter list.

function runCallback(callback: (sum: number) => void, a: number, b: number): void {
    callback(a + b);
}

// Another way of writing the function would be:
// let logSum: (sum: number) => void = function(sum: number): void {
//     console.log(sum);
// };
function logSum(sum: number): void {
    console.log(`The sum is ${sum}.`);
}

runCallback(logSum, 2, 2);