我使用JS作为产品中托管的脚本引擎,即我控制脚本在执行时看到的全局对象(相当于浏览器中的window
)。
碰巧我在JS中实现了这个全局对象,至少在顶层实现了。
从周末开始,我已成为TypeScript上瘾者,并希望声明全局对象的API。我的理想是API中丰富的功能集,无需前缀即可使用。也就是说,在用户脚本中,我希望他们能够说:
doThis();
doThat();
而不是:
myApi.doThis();
myApi.doThat();
这似乎是一件小事,但我正在构建一个特定于域的系统,前缀myApi.
将是重大噪音。
无论如何,在打字稿中我可以声明一个界面:
interface MyApi {
doThis(): void;
doThat(): void;
// Lots more...
}
然后在实现方面,我可以声明一个实现该接口的类,因此我知道我正在履行合同,并在执行用户脚本时使用该类的实例作为全局对象。
但是对于消费方,我如何声明全局对象实现MyApi
的事实?
查看lib.d.ts
,它声明interface Window
有~100个成员,然后它在前缀declare var
或declare function
的全局级别重复所有这些~100个声明添加到每个。
所以我猜我的用户必须在每次调用我的API之前输入一个前缀,否则我将不得不模仿lib.d.ts
并手动记住在两个地方复制API的每个成员(或写我自己的脚本来做这个!)
这是对的吗?
答案 0 :(得分:1)
告诉他们:
declare function doThis();
declare function doThat();
// User can simply type:
doThis();
lib.d.ts向IWindow添加内容的原因是允许用户输入window.
的内容(如果他们想要的话):
window.alert('hey');
您不希望用户键入window.doThis()
,因此您可以放心地忽略:)
如果你想支持window
,你可以简单地添加到IWindow(因为打字稿中的接口是开放式的):
interface IWindow {
doThis(): void;
doThat(): void;
}
然后用户可以同时执行window.doThis()
和doThis()
答案 1 :(得分:0)
正如我理解您的问题,您希望给用户一种方法将库方法导入用户的范围。
当lib.d.ts将其方法导出到全局(窗口)范围时,您希望具有灵活性,并允许用户将其导入自定义范围,例如 - 用户函数的范围。
这可以通过多种方式完成。最安全的是让用户决定何时在当前范围内导入库。
我可以提出这样一种方法来实现它:
//TS code sample
module DoLib {
interface DoApi {
doThis();
doThat();
}
class MyDoApi implements DoApi {
doThis(){ console.log("done this") }
doThat(){ console.log("done that") }
}
var myDoApi = new MyDoApi();
export function use(ctx){
ctx.doThis = myDoApi.doThis;
ctx.doThat = myDoApi.doThat;
//or can just iterate over all methods and add them to ctx
}
}
//JS CODE : TSC WILL NOT COMPILE
function userCode(){
DoLib.use(this);
doThis();
doThat();
}
userCode();
<强>更新强>:
我看到你不仅需要将类的接口导出到特定的范围,而且还需要将其用于TS脚本。这意味着导出的范围应该声明为TS文件,因此TS编译器可以检查其API。
Lib.d.ts执行类似的操作,但是按向后顺序 - 首先,它声明了全局类型的函数,而不是将它们再次声明为模块。
考虑到您要将API的功能导出到全局范围,声明将如下所示:
declare function doThis(p:number);
declare function doThat(s:string);
此声明引用JS上下文,而不是TS上下文。
如果TS像运行语言一样,就像JS一样,你可以使用reflecation并使用你的接口API中的声明来动态评估那些复制粘贴声明。
但事实并非如此。您可以手动执行此操作,也可以使用某种元编译器或预处理器来执行此声明。我可以建议你在文件合成引擎上使用某种直接包含。这样你就可以这样做了:
/ * DoApi.d.ts * /
//Declare to global scope
declare function doThis(p:number);
declare function doThat(s:string);
/ * DoApi.ts * /
module DoLib {
export interface DoApi {
<% inject DoApi.d.ts %>
}
export class MyDoApi implements DoApi {
doThis(n:number){ console.log("done this") }
doThat(s:string){ console.log("done that") }
}
export var myDoApi = new MyDoApi();
export function use(ctx){
ctx.doThis = myDoApi.doThis;
ctx.doThat = myDoApi.doThat;
}
}
/ * User.js * /
//your global object
var globalObject = window;
//userCode
DoLib.use(globalObject);
doThis(1);
doThat("s");