繁体   English   中英

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

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

目前我的类型定义为:

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

我需要这样的东西:

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

但是第二个没有被接受。

全局类型Function用于此目的。

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

v1.4 中的 Typescript 有type关键字,它声明了一个类型别名(类似于 C/C++ 中的typedef )。 您可以这样声明您的回调类型:

type CallbackFunction = () => void;

它声明了一个不带参数且不返回任何内容的函数。 接受零个或多个任何类型的参数并且不返回任何内容的函数将是:

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

然后你可以说,例如,

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

如果您想要一个接受任意数量参数并返回任何内容(包括 void)的函数:

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

您可以指定一些强制性参数,然后是一组附加参数(比如一个字符串、一个数字,然后是一组额外的参数),因此:

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

这对于诸如 EventEmitter 处理程序之类的东西很有用。

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

根据 Ryan 的回答,我认为您要查找的界面定义如下:

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

您可以通过多种方式在接口中定义函数类型,

  1. 一般方式:
export interface IParam {
  title: string;
  callback(arg1: number, arg2: number): number;
}
  1. 如果你想使用属性语法,那么
export interface IParam {
  title: string;
  callback: (arg1: number, arg2: number) => number;
}
  1. 如果先声明函数类型,则
type MyFnType = (arg1: number, arg2: number) => number;

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

使用非常简单,

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

    return result;
}
  1. 你也可以声明一个函数类型文字,这意味着一个函数可以接受另一个函数作为它的参数。 参数化函数也可以作为回调调用。
export interface IParam{
  title: string;
  callback(lateCallFn?:
             (arg1:number,arg2:number)=>number):number;

}

这是一个接受回调的函数示例

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

如果你不关心回调的返回值(大多数人不知道如何有效地利用它们),你可以使用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
});

注意,我用于callback参数的签名......

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

我会说这是 TypeScript 的缺陷,因为我们需要为回调参数提供一个名称 在这种情况下,我使用了_因为它在sqk函数中不可用。

然而,如果你这样做

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

它是有效的TypeScript,但它会被解释为 ...

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

即,TypeScript 会认为参数名称number而隐含的类型是any 这显然不是我们想要的,但是,这就是 TypeScript 的工作方式。

所以不要忘记在输入函数参数时提供参数名称......看起来很愚蠢。

function 类型有多种定义方式; 但是,有些比其他的要好。

尽管可以使用Function function object,但不要那样做
来源: TypeScript ESLint插件推荐规则ban-types

  • 避免使用 Function 类型,因为它提供的安全性很低,原因如下:
    • 它在调用值时不提供类型安全,这意味着很容易提供错误的 arguments。
    • 它接受 class 声明,调用时会失败,因为它们是在没有 new 关键字的情况下调用的。

TypeScript 支持其他多种方式。 最常用的是function 类型表达式 此方法与箭头函数非常相似。

如果已知 arguments 和返回值具有某种形式,则应键入它们。
例如,

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

请注意,这些类型可以根据需要复杂化,例如使用object 类型从其他类型创建的类型

如果类型确实未知,那么unknown优于any
来源:TypeScript ESLint 插件推荐规则no-explicit-any

使用any时,将忽略围绕该值的所有编译器类型检查。

从 TS 文档,

unknownany的类型安全对应物。

因此,使用传播语法

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

有四种抽象函数类型,当您知道函数是否接受参数、是否返回数据时,您可以分别使用它们。

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

像这样:

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

为了仅使用一种类型作为任何函数类型,我们可以将所有抽象类型组合在一起,如下所示:

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

然后像这样使用它:

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

在上面的例子中,一切都是正确的。 但是从大多数代码编辑器的角度来看,下面的用法示例是不正确的。

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

正确的编辑调用是这样的:

public callArgument(callback: fFunction) {

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

打字稿:如何为方法参数中使用的函数回调定义类型?

您可以将回调声明为 1)函数属性或 2)方法

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

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

TS 2.6以来,有一个重要的类型差异:

在声明函数属性时,您会在--strict--strictFunctionTypes模式下获得更强(“声音”)类型。 让我们举个例子:

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

从技术上讲,方法是双变的,函数属性在strictFunctionTypes下的参数中是逆变的 方法仍然会被更宽松地检查(即使不合理),以便与Array等内置类型结合使用更实用。

概括

  • 函数属性和方法声明之间存在类型差异
  • 如果可能,为更强的类型选择一个函数属性

游乐场示例代码

希望这会有所帮助...

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

或者在一个函数中


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

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

}

我刚刚开始使用 Typescript,我一直在尝试解决类似的问题; 如何告诉打字稿我正在传递一个没有interface的回调。

在浏览了有关 Stack Overflow 和 GitHub 问题的一些答案后,我终于找到了一个可以帮助遇到相同问题的人的解决方案。

一个函数的类型可以用(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);

如果您正在寻找输入回调 function,例如更改事件,请使用以下内容

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

在typescript 4.8中, Function类型报错。 相反,我们可以将类型显式写为fn: () => void

如果你也想使用args

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

暂无
暂无

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

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