如何使类在Typescript中实现调用签名?

Val*_*tin 31 typescript

我在typescript中定义了以下接口:

interface MyInterface {
    () : string;
}
Run Code Online (Sandbox Code Playgroud)

该接口简单地引入了一个不带参数的调用签名并返回一个字符串.如何在类中实现此类型?我尝试过以下方法:

class MyType implements MyInterface {
    function () : string {
        return "Hello World.";
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器一直告诉我

类'MyType'声明接口'MyInterface'但没有实现它:Type'MyInterface'需要一个调用签名,但Type'MyType'缺少一个

如何实现呼叫签名?

Pet*_*son 14

类无法匹配该接口.你能得到的最接近的,我认为是这个类,它将生成功能上与接口匹配的代码(但不是根据编译器).

class MyType implements MyInterface {
  constructor {
    return "Hello";
  }
}
alert(MyType());
Run Code Online (Sandbox Code Playgroud)

这将生成工作代码,但编译器会抱怨它MyType不可调用,因为它具有签名new() = 'string'(即使你调用它new,它将返回一个对象).

要在没有编译器抱怨的情况下创建与接口完全匹配的东西,您必须执行以下操作:

var MyType = (() : MyInterface => {
  return function() { 
    return "Hello"; 
  }
})();
alert(MyType());
Run Code Online (Sandbox Code Playgroud)

  • 为什么不`var MyType:MyInterface = function(){return"hello";};`那么?我认为OP的界面实际上说实现者应该是一个函数. (3认同)

teq*_*teq 9

如果可调用接口应该有其他方法,您可以这样做:

interface Greeter {
    (): void;
    setName(name: string): void;
}

class ConsoleGreeter {

    private constructor( // constructable via `create()`
        private name = 'world'
    ) {}

    public call(): void {
        console.log(`Hello ${this.name}!`);
    }

    public setName(name: string) {
        this.name = name;
    }

    public static create(): Greeter {
        const instance = new ConsoleGreeter();
        return Object.assign(
            () => instance.call(),
            {
                setName: (name: string) => instance.setName(name)
                // ... forward other methods
            }
        );
    }
}

const greeter = ConsoleGreeter.create();
greeter(); // prints 'Hello world!'
greeter.setName('Dolly');
greeter(); // prints 'Hello Dolly!'
Run Code Online (Sandbox Code Playgroud)

缺点:greeter instanceof ConsoleGreeterfalse


Sam*_*Sam 7

本回答中的代码示例假定以下声明:

var implementation: MyInterface;
Run Code Online (Sandbox Code Playgroud)

提供可调用接口的实现

作为接受的答案的后续,正如其一些评论员所建议的那样,与接口的呼叫签名匹配的函数隐式地实现了接口.因此,您可以使用任何匹配的函数作为实现.

例如:

implementation = () => "Hello";
Run Code Online (Sandbox Code Playgroud)

您无需显式指定该函数实现该接口.但是,如果要显式,可以使用强制转换:

implementation = <MyInterface>() => "Hello";
Run Code Online (Sandbox Code Playgroud)

提供可重用的实现

如果您想像通常使用Java或C#接口那样生成可重用的接口实现,只需将该函数存储在其使用者可访问的位置.

例如:

function Greet() {
    return "Hello";
}

implementation = Greet;
Run Code Online (Sandbox Code Playgroud)

提供参数化实现

您可能希望能够以与参数化类相同的方式参数化实现.这是一种方法:

function MakeGreeter(greeting: string) {
    return () => greeting;
}

implementation = MakeGreeter("Hello");
Run Code Online (Sandbox Code Playgroud)

如果希望将结果键入为接口,只需显式设置返回类型或转换返回的值.