【问题标题】:Defining TypeScript callback type定义 TypeScript 回调类型
【发布时间】:2012-10-19 16:41:33
【问题描述】:

我在 TypeScript 中有以下类:

class CallbackTest
{
    public myCallback;

    public doWork(): void
    {
        //doing some work...
        this.myCallback(); //calling callback
    }
}

我正在使用这样的类:

var test = new CallbackTest();
test.myCallback = () => alert("done");
test.doWork();

代码有效,因此它按预期显示了一个消息框。

我的问题是:我可以为我的类字段myCallback 提供任何类型吗?现在,公共字段myCallback 的类型为any,如上所示。如何定义回调的方法签名?或者我可以将类型设置为某种回调类型吗?或者我可以做这些吗?我必须使用any(隐式/显式)吗?

我尝试了类似的方法,但它不起作用(编译时错误):

public myCallback: ();
// or:
public myCallback: function;

我在网上找不到任何解释,所以希望你能帮助我。

【问题讨论】:

    标签: types callback typescript


    【解决方案1】:

    我刚刚在 TypeScript 语言规范中找到了一些东西,它相当简单。我已经很接近了。

    语法如下:

    public myCallback: (name: type) => returntype;
    

    在我的例子中,它会是

    class CallbackTest
    {
        public myCallback: () => void;
    
        public doWork(): void
        {
            //doing some work...
            this.myCallback(); //calling callback
        }
    }
    

    作为类型别名:

    type MyCallback = (name: type) => returntype;
    

    【讨论】:

    【解决方案2】:

    更进一步,您可以声明一个指向函数签名的类型指针,例如:

    interface myCallbackType { (myArgument: string): void }
    

    并像这样使用它:

    public myCallback : myCallbackType;
    

    【讨论】:

    • 这是(IMO)比接受的答案更好的解决方案,因为它允许您定义一个类型,然后,例如,传递该类型的参数(回调),然后您可以使用任何你想要的方式,包括调用它。接受的答案使用一个成员变量,您必须将成员变量设置为您的函数,然后调用一个方法 - 丑陋且容易出错,因为首先设置变量是调用该方法的合同的一部分。
    • 它还可以让您轻松地将回调设置为可为空,例如let callback: myCallbackType|null = null;
    • 请注意,TSLint 会抱怨 "TSLint: 接口只有一个调用签名 — 请改用 type MyHandler = (myArgument: string) => void。(callable-types)";见TSV's answer
    • 这个答案的早期草稿实际上解决了导致我提出这个问题的问题。我一直试图在一个接口中定义一个足够宽松的函数签名,它可以接受任意数量的参数而不会产生编译器错误。我的答案是使用...args: any[]。示例:export interface MyInterface { /** 一个回调函数。 / callback: (...args: any[]) => any, /* 回调函数的参数。 */ callbackParams: any[] }
    【解决方案3】:

    你可以声明一个新类型:

    declare type MyHandler = (myArgument: string) => void;
    
    var handler: MyHandler;
    

    更新。

    declare 关键字不是必需的。它应该在 .d.ts 文件或类似情况下使用。

    【讨论】:

    • 我在哪里可以找到这方面的文档?
    • @E.Sundin - typescriptlang.org/docs/handbook/advanced-types.html 的“类型别名”部分
    • 虽然确实很高兴知道,但同一页面(现在)还声明 “因为软件的理想属性是对扩展开放的,所以您应该始终在类型别名上使用接口,如果可能。”
    • @Arjan - 对于对象,我完全同意这一点。您能否指定 - 您想如何扩展功能?
    • 请注意,类型声明是可选的:var handler: (myArgument: string) => void 在语法上是有效的(如果有点乱)。
    【解决方案4】:

    这是一个例子 - 不接受任何参数并且不返回任何内容。

    class CallbackTest
    {
        public myCallback: {(): void;};
    
        public doWork(): void
        {
            //doing some work...
            this.myCallback(); //calling callback
        }
    }
    
    var test = new CallbackTest();
    test.myCallback = () => alert("done");
    test.doWork();
    

    如果你想接受一个参数,你也可以添加它:

    public myCallback: {(msg: string): void;};
    

    如果你想返回一个值,你也可以添加:

    public myCallback: {(msg: string): number;};
    

    【讨论】:

    • 在功能上它们是相同的——它们定义了相同的东西并让你对函数签名进行类型检查。你可以使用任何你喜欢的。规范说他们是exactly equivalent
    • @nikeee:问题是你的答案有什么不同?史蒂夫在你之前发布了他的答案。
    • @jgauffin 确实,结果是一样的。 IMO 我发布的解决方案在谈论回调时更自然,因为史蒂夫的版本允许整个接口定义。这取决于您的喜好。
    • @Fenton 您能否提供该文档的链接?
    【解决方案5】:

    如果你想要一个通用函数,你可以使用下面的。虽然它似乎没有记录在任何地方。

    class CallbackTest {
      myCallback: Function;
    }   
    

    【讨论】:

      【解决方案6】:

      您可以使用以下内容:

      1. 类型别名(使用type 关键字,给函数文字起别名)
      2. 接口
      3. 函数字面量

      以下是如何使用它们的示例:

      type myCallbackType = (arg1: string, arg2: boolean) => number;
      
      interface myCallbackInterface { (arg1: string, arg2: boolean): number };
      
      class CallbackTest
      {
          // ...
      
          public myCallback2: myCallbackType;
          public myCallback3: myCallbackInterface;
          public myCallback1: (arg1: string, arg2: boolean) => number;
      
          // ...
      
      }
      

      【讨论】:

        【解决方案7】:

        我有点晚了,但是,因为前段时间在 TypeScript 中,您可以使用

        定义回调的类型
        type MyCallback = (KeyboardEvent) => void;
        

        使用示例:

        this.addEvent(document, "keydown", (e) => {
            if (e.keyCode === 1) {
              e.preventDefault();
            }
        });
        
        addEvent(element, eventName, callback: MyCallback) {
            element.addEventListener(eventName, callback, false);
        }
        

        【讨论】:

          【解决方案8】:

          这是我如何定义包含回调的接口的简单示例。

          // interface containing the callback
          
          interface AmazingInput {
              name: string
              callback: (string) => void  //defining the callback
          }
          
          // method being called
          
          public saySomethingAmazing(data:AmazingInput) {
             setTimeout (() => {
               data.callback(data.name + ' this is Amazing!');
             }, 1000)
          
          }
          
          // create a parameter, based on the interface
          
          let input:AmazingInput = {
              name: 'Joe Soap'
              callback: (message) => {
                  console.log ('amazing message is:' + message);
              }
          }
          
          // call the method, pass in the parameter
          
          saySomethingAmazing(input);
          
          

          【讨论】:

          • 在 TypeScript 中,您无法在没有名称的情况下定义函数参数的类型。你不能做(string) => void。它必须类似于(param: string) => void(_:string) => void。不过,您使用的语法在 Dart 等其他语言中也是有效的。
          【解决方案9】:

          我在尝试将回调添加到事件侦听器时遇到了同样的错误。奇怪的是,将回调类型设置为 EventListener 解决了它。它看起来比将整个函数签名定义为类型更优雅,但我不确定这是否是正确的方法。

          class driving {
              // the answer from this post - this works
              // private callback: () => void; 
          
              // this also works!
              private callback:EventListener;
          
              constructor(){
                  this.callback = () => this.startJump();
                  window.addEventListener("keydown", this.callback);
              }
          
              startJump():void {
                  console.log("jump!");
                  window.removeEventListener("keydown", this.callback);
              }
          }
          

          【讨论】:

          • 喜欢它。但是另一个班级在哪里?
          【解决方案10】:

          这是 Angular 组件和服务的可选回调函数示例

              maincomponent(){
                  const param = "xyz";
                 this.service.mainServie(param, (response)=>{
                  if(response){console.log("true");}
                  else{console.log("false");}
                })
              }
          
          //Service Component
              mainService(param: string, callback?){
                if(string === "xyz"){
                  //call restApi 
                  callback(true);
                }
              else{
                  callback(false);
                }
              }
          

          【讨论】:

          • 您的示例侧重于 99.99% 的 JavaScript,而不是 TypeScript。除了可能将其声明为undefined(通过后缀?:callback?)之外,您的callback 参数没有附加类型。所以你的callback 的类型是any | undefined
          猜你喜欢
          • 2017-07-07
          • 2021-02-24
          • 2017-12-21
          • 2019-04-01
          • 1970-01-01
          • 2022-10-12
          • 2021-03-26
          • 2016-06-22
          • 1970-01-01
          相关资源
          最近更新 更多