如何编写实现此TypeScript接口的类(并保持TypeScript编译器满意):
interface MyInterface {
(): string;
text2(content: string);
}
我看到了这个相关的答案: How to make a class implement a call signature in Typescript?
但是只有在接口只有裸功能签名时才有效。如果要实现其他成员(例如函数text2),它将不起作用。
答案 0 :(得分:43)
类无法实现typescript接口中可用的所有内容。两个主要的例子是可调用的签名和索引操作,例如:Implement an indexible interface
原因是界面主要用于描述JavaScript对象可以执行的任何操作。因此,它需要非常强大。然而,TypeScript类被设计为以更OO传统/易于理解/易于类型的方式专门表示原型继承。
您仍然可以创建一个跟随该界面的对象:
interface MyInterface {
(): string;
text2(content: string);
}
var MyType = ((): MyInterface=>{
var x:any = function():string { // Notice the any
return "Some string"; // Dummy implementation
}
x.text2 = function(content:string){
console.log(content); // Dummy implementation
}
return x;
}
);
答案 1 :(得分:14)
使用ES6的Object.assign
有一种简单且类型安全的方法:
const foo: MyInterface = Object.assign(
// Callable signature implementation
() => 'hi',
{
// Additional properties
text2(content) { /* ... */ }
}
)
当我最初询问和回答这个问题时,我认为在TypeScript中没有提供的交叉点类型是获得正确输入的秘诀。
答案 2 :(得分:9)
以下是the accepted answer的详细说明。
据我所知,实现调用签名的唯一方法是使用函数/方法。要实现其余成员,只需在此函数上定义它们即可。对于来自C#或Java的开发人员来说,这似乎很奇怪,但我认为这在JavaScript中是正常的。
在JavaScript中,这很简单,因为您只需定义函数然后添加成员即可。但是,TypeScript的类型系统不允许这样做,因为在此示例中,Function
未定义text2
成员。
因此,要获得所需的结果,您需要在定义函数的成员时绕过类型系统,然后可以将结果转换为接口类型:
//A closure is used here to encapsulate the temporary untyped variable, "result".
var implementation = (() => {
//"any" type specified to bypass type system for next statement.
//Defines the implementation of the call signature.
var result: any = () => "Hello";
//Defines the implementation of the other member.
result.text2 = (content: string) => { };
//Converts the temporary variable to the interface type.
return <MyInterface>result;
})(); //Invokes the closure to produce the implementation
请注意,您不需要使用闭包。您可以在与生成的接口实现相同的范围内声明临时变量。另一种选择是命名闭包函数以提高可读性。
我认为这是一个更现实的例子:
interface TextRetriever {
(): string;
Replace(text: string);
}
function makeInMemoryTextRetriever(initialText: string) {
var currentText = initialText;
var instance: any = () => currentText;
instance.Replace = (newText: string) => currentText = newText;
return <TextRetriever>instance;
}
var inMemoryTextRetriever = makeInMemoryTextRetriever("Hello");