简体   繁体   English

如何定义方法参数中使用的 function 回调类型(作为任何 function 类型,不是通用类型)

[英]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.但是第二个没有被接受。

The global type Function serves this purpose.全局类型Function用于此目的。

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.此外,如果您打算使用 0 个参数调用此回调并忽略其返回值,则类型() => void匹配所有不带参数的函数。

Typescript from v1.4 has the type keyword which declares a type alias (analogous to a typedef in C/C++). v1.4 中的 Typescript 有type关键字,它声明了一个类型别名(类似于 C/C++ 中的typedef )。 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):如果您想要一个接受任意数量参数并返回任何内容(包括 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.这对于诸如 EventEmitter 处理程序之类的东西很有用。

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.函数可以以这种方式按您喜欢的强类型进行输入,但是如果您尝试使用类型别名来确定所有内容,则可能会被带走并遇到组合问题。

Following from Ryan's answer, I think that the interface you are looking for is defined as follows:根据 Ryan 的回答,我认为您要查找的界面定义如下:

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

You can define a function type in interface in various ways,您可以通过多种方式在接口中定义函数类型,

  1. general way:一般方式:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. If you would like to use property syntax then,如果你想使用属性语法,那么
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. 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;
}
  1. 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;

}

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如果你不关心回调的返回值(大多数人不知道如何有效地利用它们),你可以使用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 ...注意,我用于callback参数的签名......

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.我会说这是 TypeScript 的缺陷,因为我们需要为回调参数提供一个名称 In this case I used _ because it's not usable inside the sqk function.在这种情况下,我使用了_因为它在sqk函数中不可用。

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 ...它是有效的TypeScript,但它会被解释为 ...

// 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 .即,TypeScript 会认为参数名称number而隐含的类型是any This is obviously not what we intended, but alas, that is how TypeScript works.这显然不是我们想要的,但是,这就是 TypeScript 的工作方式。

So don't forget to provide the parameter names when typing your function parameters... stupid as it might seem.所以不要忘记在输入函数参数时提供参数名称......看起来很愚蠢。

There are various ways to define function types; function 类型有多种定义方式; however, some are better than others.但是,有些比其他的要好。

Although it is possible to use Function , the JavaScript function object, don't do that .尽管可以使用Function function object,但不要那样做
Source: TypeScript ESLint plugin recommended rule ban-types来源: TypeScript ESLint插件推荐规则ban-types

  • Avoid the Function type, as it provides little safety for the following reasons:避免使用 Function 类型,因为它提供的安全性很低,原因如下:
    • It provides no type safety when calling the value, which means it's easy to provide the wrong arguments.它在调用值时不提供类型安全,这意味着很容易提供错误的 arguments。
    • It accepts class declarations, which will fail when called, as they are called without the new keyword.它接受 class 声明,调用时会失败,因为它们是在没有 new 关键字的情况下调用的。

TypeScript supports multiple other ways. TypeScript 支持其他多种方式。 Most commonly, function type expressions are used.最常用的是function 类型表达式 This method highly resembles arrow functions .此方法与箭头函数非常相似。

If arguments and return values are known to be of a certain form, then they should be typed.如果已知 arguments 和返回值具有某种形式,则应键入它们。
For example,例如,

interface Param {
  callback: (foo: string, bar: number) => void
}

Note that these types can be as complex as needed, for example using object types or types created from other types .请注意,这些类型可以根据需要复杂化,例如使用object 类型从其他类型创建的类型

If the types are truly unknown then prefer unknown over any .如果类型确实未知,那么unknown优于any
Source: TypeScript ESLint plugin recommended rule no-explicit-any来源:TypeScript ESLint 插件推荐规则no-explicit-any

When any is used, all compiler type checks around that value are ignored.使用any时,将忽略围绕该值的所有编译器类型检查。

From the TS docs,从 TS 文档,

unknown is the type-safe counterpart of any . unknownany的类型安全对应物。

Thus , using spread syntax ,因此,使用传播语法

interface Params {
  callback: (...args: unknown[]) => unknown
}

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

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 :您可以将回调声明为 1)函数属性或 2)方法

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 :TS 2.6以来,有一个重要的类型差异:

You get stronger ("sound") types in --strict or --strictFunctionTypes mode, when a function property is declared.在声明函数属性时,您会在--strict--strictFunctionTypes模式下获得更强(“声音”)类型。 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 .从技术上讲,方法是双变的,函数属性在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 .方法仍然会被更宽松地检查(即使不合理),以便与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 游乐场示例代码

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;

}

I've just started using Typescript and I've been trying to solve a similar problem like this;我刚刚开始使用 Typescript,我一直在尝试解决类似的问题; how to tell the Typescript that I'm passing a callback without an interface .如何告诉打字稿我正在传递一个没有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.在浏览了有关 Stack Overflow 和 GitHub 问题的一些答案后,我终于找到了一个可以帮助遇到相同问题的人的解决方案。

A function's type can be defined with (arg0: type0) => returnType and we can use this type definition in another function's parameter list.一个函数的类型可以用(arg0: type0) => returnType定义,我们可以在另一个函数的参数列表中使用这个类型定义。

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

If you are looking for input callback function like on change event then use the following如果您正在寻找输入回调 function,例如更改事件,请使用以下内容

type Props = {
  callBack:  ChangeEventHandler<HTMLInputElement>;
}

In typescript 4.8, Function type gives error.在typescript 4.8中, Function类型报错。 Instead we can write the type explicitly as fn: () => void .相反,我们可以将类型显式写为fn: () => void

If you want to use args as well,如果你也想使用args

function debounce(fn: (...args: any[]) => void, ms = 300) {

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM