在TypeScript中,我可以声明当前作用域包含接口的所有成员吗?

时间:2014-03-05 11:47:32

标签: typescript

我使用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 vardeclare function的全局级别重复所有这些~100个声明添加到每个。

所以我猜我的用户必须在每次调用我的API之前输入一个前缀,否则我将不得不模仿lib.d.ts并手动记住在两个地方复制API的每个成员(或写我自己的脚本来做这个!)

这是对的吗?

2 个答案:

答案 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");