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

Smr*_*ahu 248 javascript typescript

目前我的类型定义为:

interface Param {
    title: string;
    callback: any;
}
Run Code Online (Sandbox Code Playgroud)

我需要这样的东西:

interface Param {
    title: string;
    callback: function;
}
Run Code Online (Sandbox Code Playgroud)

但第二个不被接受.

Rya*_*ugh 237

全局类型Function用于此目的.

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

  • [基本类型]中缺少这个东西(https://www.typescriptlang.org/docs/handbook/basic-types.html) (22认同)
  • 它不是基本类型,因为您应该定义参数并返回值.回调之类:(数字:数字)=>无效; 对于类型检查比回调更有用:function; 将会. (9认同)
  • 请注意,[ESLint 给出了一些使用 `Function` 的建议](https://github.com/typescript-eslint/typescript-eslint/blob/v4.33.0/packages/eslint-plugin/docs/rules/ban-types。 md) 直接作为类型 -- quote “不要使用 `Function` 作为类型。`Function` 类型接受任何类似函数的值。它在调用函数时不提供类型安全性,这可能是bug。它还接受类声明之类的东西,这些东西会在运行时抛出,因为它们不会被`new`调用。” (9认同)
  • FWIW,关于函数类型的文档可用 [here](https://www.typescriptlang.org/docs/handbook/interfaces.html#function-types) (2认同)
  • @SgtPooki 鉴于 [Ryan 是 Typescript 团队的领导](https://github.com/RyanCavanaugh) 并且您的编辑非常重要,您确定它们更多地属于编辑而不是您自己的答案吗?我认为你的补充是有效的建议,但考虑到 Ryan 的权威,我很惊讶地发现你的编辑在这里,特别是在它们[与原始帖子相矛盾或_改变了含义]的地方](https://stackoverflow.com/help/editing)。 (2认同)
  • 感谢您的 ping @JeffBowman;我已经恢复了 (2认同)
  • @jeff-bowman 足够公平了。事后看来,我完全同意我的编辑应该是它自己的答案。然而,无意冒犯 Ryan,但 Ryan 的立场与是否应更新他之前发布的答案的改进无关。如果由于人们的立场而不允许我们编辑过时的答案,那么 stackoverflow 将是一个不太有用的地方。另外,[_预计编辑量会很大,并且使帖子比您发现的更好_](https://stackoverflow.com/help/editing)。这个答案**需要**更新。不管怎样。 (2认同)
  • @SgtPooki Ryan 的正确:编辑可能很大,但应该_保留答案的含义_。如果任何人都可以自由地将评分最高的答案更改为他们认为正确的答案,那么这些答案的排名/投票就会失去任何价值。如果您认为答案的核心含义需要更新,请发表评论和/或编写新答案。至于你关于作者立场的观点:这些关于尊重原作者的规则适用于每个人,但是_来自权威来源的高度可见和高票数的答案_是行使该规则的特别好的地方。 (2认同)

Dav*_*d G 159

v1.4中的Typescript具有type声明类型别名的关键字(类似于typedefC/C++中的a).您可以声明您的回调类型:

type CallbackFunction = () => void;
Run Code Online (Sandbox Code Playgroud)

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

type CallbackFunctionVariadic = (...args: any[]) => void;
Run Code Online (Sandbox Code Playgroud)

然后你可以说,例如,

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

如果你想要一个带有任意数量参数并返回任何东西的函数(包括void):

type CallbackFunctionVariadicAnyReturn = (...args: any[]) => any;
Run Code Online (Sandbox Code Playgroud)

您可以指定一些必需参数,然后指定一组其他参数(比如一个字符串,一个数字,然后是一组额外的参数),因此:

type CallbackFunctionSomeVariadic =
  (arg1: string, arg2: number, ...args: any[]) => void;
Run Code Online (Sandbox Code Playgroud)

这对于像EventEmitter处理程序这样的东西很有用.

函数可以以这种方式强烈地输入,尽管如果你试图用类型别名来解决所有问题,你可能会被带走并遇到组合问题.

  • 在 `Function` 和 `(...args: any[]) => any` 之间,哪个更好? (4认同)

blo*_*ish 56

根据Ryan的回答,我认为您正在寻找的界面定义如下:

interface Param {
    title: string;
    callback: () => void;
}
Run Code Online (Sandbox Code Playgroud)


Der*_*ers 36

定义函数类型的方法有很多种;然而,有些比其他更好。

尽管可以使用FunctionJavaScript 函数对象,但不要这样做
来源:TypeScript ESLint 插件推荐规则ban-types

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

TypeScript 支持多种其他方式。例如,函数类型表达式该方法与箭头函数非常相似。

如果已知参数和返回值具有某种形式,那么应该对它们进行类型化。回调 应该是这种情况。
例如,

interface Param {
  callback: (foo: string, bar: number) => void
}
Run Code Online (Sandbox Code Playgroud)

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

如果类型确实未知,unknown优先选择any.
来源:TypeScript ESLint 插件推荐规则no-explicit-any

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

从 TS 文档中,

unknown是 的类型安全对应项any

因此,使用扩展语法

interface Param {
  callback: (...args: unknown[]) => unknown
}
Run Code Online (Sandbox Code Playgroud)

  • 这是最简洁的答案,应该被接受。 (2认同)

Tha*_*you 30

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

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
});
Run Code Online (Sandbox Code Playgroud)

如果你不关心回调的返回值(大多数人不知道如何以任何有效的方式使用它们),你可以使用 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
});
Run Code Online (Sandbox Code Playgroud)

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

const sqk = (x: number, callback: ((_: number) => number)): number
Run Code Online (Sandbox Code Playgroud)

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

但是,如果你这样做

// danger!! don't do this
const sqk = (x: number, callback: ((number) => number)): number
Run Code Online (Sandbox Code Playgroud)

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

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

即,TypeScript会认为参数名称number隐含的类型any.这显然不是我们想要的,但唉,这就是TypeScript的工作原理.

因此,在键入函数参数时不要忘记提供参数名称......看似愚蠢.


Hum*_*bir 22

您可以通过各种方式在界面中定义函数类型,

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

export interface IParam {
  title: string;
  callback: MyFnType;
}
Run Code Online (Sandbox Code Playgroud)

使用非常直接,

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

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

}
Run Code Online (Sandbox Code Playgroud)


小智 18

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

export declare type fEmptyVoid = () => void;
export declare type fEmptyReturn = () => any;
export declare type fArgVoid = (...args: any[]) => void;
export declare type fArgReturn = (...args: any[]) => any;
Run Code Online (Sandbox Code Playgroud)

像这样:

public isValid: fEmptyReturn = (): boolean => true;
public setStatus: fArgVoid = (status: boolean): void => this.status = status;
Run Code Online (Sandbox Code Playgroud)

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

export declare type fFunction = fEmptyVoid | fEmptyReturn | fArgVoid | fArgReturn;
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它:

public isValid: fFunction = (): boolean => true;
public setStatus: fFunction = (status: boolean): void => this.status = status;
Run Code Online (Sandbox Code Playgroud)

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

// 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();
}
Run Code Online (Sandbox Code Playgroud)

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

public callArgument(callback: fFunction) {

    // pay attention in this part, for fix editor(s) error
    (callback as fFunction)();
}
Run Code Online (Sandbox Code Playgroud)


小智 9

希望这会有所帮助...

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

Run Code Online (Sandbox Code Playgroud)

或者在一个函数中


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

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

}

Run Code Online (Sandbox Code Playgroud)


for*_*d04 5

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

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

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

interface ParamMethod {
    callback(a: Animal): void; // method
}
Run Code Online (Sandbox Code Playgroud)

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

当一个函数属性被声明时,你会在--strictor--strictFunctionTypes模式中获得更强的(“声音”)类型。让我们举个例子:

const animalCallback = (a: Animal): void => { } // Animal is the base type for Dog
const dogCallback = (d: Dog): void => { } 
Run Code Online (Sandbox Code Playgroud)
// 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 ...
Run Code Online (Sandbox Code Playgroud)

从技术上说,方法是双变量和函数属性逆变下他们的观点strictFunctionTypes。方法仍然被更宽松地检查(即使不是健全的),以便与内置类型(如Array.

概括

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

游乐场示例代码