如何让一个类在 Typescript 中实现调用签名?
Posted
技术标签:
【中文标题】如何让一个类在 Typescript 中实现调用签名?【英文标题】:How to make a class implement a call signature in Typescript? 【发布时间】:2012-09-27 23:45:51 【问题描述】:我在 typescript 中定义了如下接口:
interface MyInterface
() : string;
这个接口只是引入了一个不带参数并返回一个字符串的调用签名。如何在类中实现这种类型?我尝试了以下方法:
class MyType implements MyInterface
function () : string
return "Hello World.";
编译器一直告诉我
“MyType”类声明了“MyInterface”接口,但没有实现它:“MyInterface”类型需要调用签名,但“MyType”类型缺少调用签名
如何实现调用签名?
【问题讨论】:
为了它的价值,我filed an issue related to this。 在这种情况下,MyInterface 的行为有点像 typedef:它定义了一个始终返回字符串的函数。这是函数的子类型,可用于将类型分配给任何函数,不带参数并返回字符串。一种新型。类在 JS 中产生经典模式,调用它们产生 Object,所以类不能实现这个接口。基本上只有当它们不被称为构造函数(即使用 new)时才可以。 解决方案也有类似的问题:***.com/questions/13136892/overload-implementation/… 【参考方案1】:类不能匹配那个接口。你能得到的最接近的,我认为是这个类,它将生成在功能上与接口匹配的代码(但不是根据编译器)。
class MyType implements MyInterface
constructor
return "Hello";
alert(MyType());
这将生成工作代码,但编译器会抱怨MyType
不可调用,因为它具有签名new() = 'string'
(即使您使用new
调用它,它也会返回一个对象)。
要创建与界面完全匹配且编译器不会抱怨的东西,您必须执行以下操作:
var MyType = (() : MyInterface =>
return function()
return "Hello";
)();
alert(MyType());
【讨论】:
那为什么不var MyType : MyInterface = function() return "hello";;
呢?我认为 OP 的接口实际上是说实现者应该是一个函数。
@kahoon 我认为 OP 希望实现者是一个返回字符串的函数。
@PeterOlson 那么在接口定义中添加CallSignatures
有什么意义呢?
@valentin 你可以拥有一个不仅仅是类的接口
实际上你不需要创建如此复杂的声明 :-) 我的意思是在这种情况下不需要嵌套匿名函数。【参考方案2】:
如果可调用接口应该有其他方法,你可以这样做:
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!'
缺点:greeter instanceof ConsoleGreeter
是 false
【讨论】:
您为什么决定在Object.assign
调用中编写所有函数调用程序?你为什么不直接写Object.assign(instance.call, instance);
?
@RobertKoritnik 我这样做是为了简单起见。可以引入一个不需要转发每个实例方法的通用解决方案,但它不会像您建议的那么简单...... 1.需要将call
方法绑定到instance
,否则@987654328当您调用 call
时,@ 将是 undefined
。 2.Object.assign
复制一个源对象的所有可枚举的OWN属性,但instance
通过原型链继承所有方法。
是的,当我尝试实现自定义 angularjs IHttpService
时,我也意识到了同样的情况,它也具有隐式调用签名。有趣的是Object.assign
的第一个参数是一个函数而不是一个对象。这几乎感觉就像创建一个带有静态成员的类(构造函数)(不是原型的一部分,而是直接构造函数的一部分)。【参考方案3】:
此答案中的代码示例假定以下声明:
var implementation: MyInterface;
提供可调用接口的实现
作为the accepted answer 的后续行动,正如它的一些评论者所建议的那样,匹配接口调用签名的函数隐式实现了接口。所以你可以使用任何匹配的函数作为实现。
例如:
implementation = () => "Hello";
您不需要明确指定函数实现接口。但是,如果您想明确,可以使用强制转换:
implementation = <MyInterface>() => "Hello";
提供可重用的实现
如果您想像通常使用 Java 或 C# 接口一样生成接口的可重用实现,只需将该函数存储在其使用者可访问的位置。
例如:
function Greet()
return "Hello";
implementation = Greet;
提供参数化实现
您可能希望能够以与参数化类相同的方式参数化实现。这是执行此操作的一种方法:
function MakeGreeter(greeting: string)
return () => greeting;
implementation = MakeGreeter("Hello");
如果您希望将结果类型化为接口,只需显式设置返回类型或强制转换返回的值即可。
【讨论】:
以上是关于如何让一个类在 Typescript 中实现调用签名?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 React TypeScript 中实现 e 和 props?