【问题标题】:Asynchronous load of TypeScript declarations with no exports异步加载没有导出的 TypeScript 声明
【发布时间】:2012-10-12 12:38:08
【问题描述】:

我有许多 jQuery 插件,我想在 TypeScript 中使用 AMD 模式加载它们。例如,我可能有这样的结构:

/lib/jquery.myplugin.js
/app.ts

该插件只是扩展了 jQuery。它没有提供新的顶级函数或变量。一个例子可能是:

// jquery.myplugin.js
jQuery.fn.myExample = function() { ... }

对应的 jquery.myplugin.d.ts 文件如下:

interface JQuery {
    myExample();
}

所以现在在 app.ts 中我可以调用类似 $('#my-element').myExample() 的东西。请注意,这假设我已经加载了 Microsoft 的 jquery.d.ts 声明。

我的问题是如何异步加载这个库并利用 TypeScripts 静态类型?我可以这样使用它:

/// <reference path="lib/jquery.myplugin.d.ts"/>

但这需要我在我的 HTML 中添加一个 &lt;script&gt; 标记,并且该库不是异步加载的。我希望 TypeScript 生成此代码:

define(["require", "exports", "lib/jquery.myplugin"], function (require, exports, __jquery.myplugin__) {
    ...
    // Use my plugin
    $('#my-element').myExample();
}

但是,由于 .d.ts 文件中没有导出,我无法编写 import myplugin = module('lib/jquery.myplugin')

我得到的最接近的方法是创建一个jquery.myplugin.d.ts,它引用另一个带有接口声明的 ts 文件,并且至少包含一个导出。然而,在这个库中没有什么要导出的,为了获得所需的输出,我不仅要添加一个导出,而且我必须调用它。

更新:我在typescript.codeplex.com上为此打开了work item

【问题讨论】:

  • 我当前的解决方法是在我的 TypeScript 代码中手动调用 require([...], () =&gt; { ... }),这会生成嵌套的 require 调用。远非理想,但它确实有效。

标签: javascript typescript js-amd


【解决方案1】:

Typescript 不会导入模块,除非它们导出某些内容,除非您直接使用它们导出的内容,但是对于像 JQuery 插件这样简单地将新方法添加到 $.解决方案是使用 here 中记录的 amd-dependency 标志。

在文件顶部添加这样一行:

///<amd-dependency path="jgrowl" />

这将强制 Typescript 将其列在已编译 Javascript 的 define 调用中。您还需要在 require.config 中为您的插件设置路径和填充程序,如下所示:

require.config({
  paths: {
    jquery: "external/jquery-2.1.1",
    jgrowl: "external/jquery.jgrowl-1.4.0.min",
  },
  shim: {
    'jgrowl': { deps: ['jquery'] },
  }
});

【讨论】:

  • 非常好,非常感谢。当我问这个问题时,我认为这个功能不存在。这看起来正是我想要的。
【解决方案2】:

在定义接口的文件底部可以放:

export var JQuery: JQueryStatic;

这将使 JQuery 的智能感知显示在使用 import module 加载的任何文件上。

如果您的文件是异步加载的,并且您将 JQuery 设置为另一个变量(即 myJQuery),您可以声明该文件已经被某个特定的例如,如果您的///&lt;reference path=...&gt; 中有该文件,您应该可以使用:

declare var myJQuery: JQuery;

使您的 myJQuery 类型为 JQuery

另一个技巧是将接口直接插入到异步加载代码的区域:

interface JQueryStatic {
    myFunc(): string;
}

如果您不介意编辑您的 JQuery.d.ts 文件,您可以将您的函数添加到其中定义的接口中。

与您的示例相关,您应该能够执行以下操作:

declare var __jquery : JQueryStatic;

在定义回调的顶部;并且如果您扩展了 JQueryStatic 的接口并使用 ///&lt;reference path=...&gt; 将其包含在内,则标记应该可以正常工作。

【讨论】:

  • 我自己没用过AMD,希望对你有帮助!
  • 声明全局变量适用于您通过其他方式加载的库,例如。 HTML 中的脚本标记。 AMD 模式的好处是它允许您声明您的依赖项并在构建时根据需要加载或捆绑它,并且您的全局命名空间不必被污染。对于没有顶级导出的库,TypeScript 没有很好地支持这一点。
  • 对不起,我认为 AMD 模式对回调样式起作用了?如果是这样,那么是否可以在回调中使用 JQuery 接口声明一个变量?然后它将仅在回调中而不是在文件的其余部分中显示为智能感知。
  • 问题不在于 AMD 模式的功能,而在于 TypeScript 在模块和 AMD 模式之间的集成。没有办法让 TypeScript 编译器使用当前实现中的模块生成正确的 define 调用。
  • 好的,我明白了。您一直想生成define 函数。我以为你只是想要intellisense 用于回调参数列表中声明的所有变量。对不起! :)
【解决方案3】:

有点骇人听闻,但这是我目前知道的唯一方法。

myplugin.d.ts:扩展 JQueryStatic 接口以包含用于 myplugin 功能的智能感知

/// <reference path="../dep/jquery/jquery.d.ts" />

interface JQueryStatic {
    myFunc(): string;
}

myplugin.ts:一个虚拟文件,其唯一目的是让 typescript 生成一个 amd 模块定义。

var test: number = 1;

consumer.ts

/// <reference path="myplugin.d.ts" />

import myplugin = module('myplugin');

// without this typescript knows you aren't actually using the module
// and won't create the define block including your plugin
var workaround = myplugin.test;

$.myFunc();

consumer.js:使用tsc -c --module amd consumer.ts生成

define(["require", "exports", 'myplugin'], function(require, exports, __myplugin__) {
    /// <reference path="myplugin.d.ts" />
    var myplugin = __myplugin__;

    // without this typescript knows you aren't actually using the module
    // and won't create the define block including your plugin
    var workaround = myplugin.test;
    $.myFunc();
})

请注意,myplugin.d.ts 将为 jQuery 和您的插件定义引入智能感知。有必要同时创建 myplugin.d.ts 和 myplugin.ts,因为我不知道如何(如果可能)导出某些内容,同时在同一个文件中扩展现有接口而不会出错。

【讨论】:

  • 看来您还必须在 requirejs 配置(或您正在使用的任何 AMD 加载程序)中定义一个将“myplugin”与插件路径相关联的路径,对吗?否则,如果你把 myplugin.d.ts 和插件放在同一个位置,编译出来的 js 文件会覆盖你的插件库。
  • 仅当您使用定义标志运行编译器并且未指定备用输出目录时。默认情况下它只会输出 myplugin.js。
  • 我是说 myplugin.js 在这种情况下可能是您的库的名称。在我的示例中,我将导入“lib/jquery.myplugin”。因此,如果不对依赖项名称起别名,您生成的 JavaScript 文件将覆盖您的库。
  • @dcstraw 它不会覆盖你的库,因为它会创建一个名为 myplugin.d.js 而不是 myplugin.js 的文件。
  • @Sohnee 我从未见过 tsc 生成 .d.js 文件。 .d.ts 文件没有输出,.ts 文件生成 .js 文件。
猜你喜欢
  • 2017-05-31
  • 2018-09-23
  • 2016-12-06
  • 2020-03-22
  • 2017-01-05
  • 1970-01-01
  • 2018-07-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多