使用SystemJS导入时出现问题

3
我将尝试使用现有的js库(validate.js)在客户端和服务器上进行操作。
我已使用npm安装了该库,并且编译后适用于服务器和客户端。
在服务器中使用它时,它很好地工作,但在浏览器中执行时会抛出错误。
在两种情况下使用相同的文件:
import validate = require("validate.js");

export function RequestValidator(data: any): any {
    return (validate as any)(data, constraints, { allowEmpty: true });
}

validate 被断言为 any,否则将会出现以下错误:

TS2349: Cannot invoke an expression whose type lacks a call signature.

我使用的是以下的 .d.ts 文件:

declare module "validate.js" {
    export interface ValidateJS {
        (attributes: any, constraints: any, options?: any): any;
        async(attributes: any, constraints: any, options?: any): Promise<any>;
        single(value: any, constraints: any, options?: any): any;
    }

    export const validate: ValidateJS;
    export default validate;
}

该模块只导出一个函数,在服务器上运行良好,但在客户端调用此函数时出现以下问题:
Uncaught TypeError: validate is not a function(…)

代码使用目标commonjs来编译服务器端。
"use strict";
const validate = require("validate.js");
...

客户端的 system

System.register(["validate.js"], function(exports_1, context_1) {
    "use strict";
    var __moduleName = context_1 && context_1.id;
    var validate;
    ...

    return {
        setters:[
            function (validate_1) {
                validate = validate_1;
            }],
    ...

在调试时,validate 确实不是一个函数,而是:
validate: r
    EMPTY_STRING_REGEXP: (...)
    get EMPTY_STRING_REGEXP: function()
    set EMPTY_STRING_REGEXP: function()
    Promise: (...)
    get Promise: function()
    set Promise: function()
    __useDefault: (...)
    get __useDefault: function()
    set __useDefault: function()
    async: (...)
    get async: function()
    set async: function()
    capitalize: (...)
    get capitalize: function()
    set capitalize: function()
    cleanAttributes: (...)
    get cleanAttributes: function()
    set cleanAttributes: function()
    ...

有什么想法,为什么它在浏览器中会以这种方式表现?

1
请看这段关于CommonJS的最后一句话:https://github.com/systemjs/systemjs/blob/master/docs/module-formats.md#commonjs。SystemJS加载CommonJS模块的方式与NodeJS并不完全相同。虽然有`@node`,但我个人没有使用过这种黑魔法。 - martin
@martin 好啊,这不是太好了吗。我特别喜欢:“只有在绝对必要的情况下才应使用它,因为它会阻止代码成为通用的,并使其仅与NodeJS兼容”。那么现在我也被迫使用 jspm 了吗? - Nitzan Tomer
我自己从未使用过那个选项,我只是记得在那里看到它被提到过... - martin
1个回答

3
当您使用"module": "system"编译时,可以进行与Node兼容的导入。
import validate = require("validate.js");

不再起作用 - 您获取的validate值是一个模块,而不是函数。这可能是typescript的错误,也可能是设计上的问题 - 我不知道。(更新:从github评论中针对JsonFreeman 在这里,看起来是故意这样设计的:您可以通过一组属性获取模块对象,包括一个名为default的属性)。
有几种解决方法:
首先,您可以自己进行简单的转换 - 您需要的函数作为模块的default属性提供,因此这行代码会将其修复:
validate = validate.default ? validate.default : validate;

或者,即使是在浏览器中,您也可以使用"module": "commonjs"进行编译,这样TypeScript将生成可工作的代码,systemjs将自动检测模块的格式。

或者最后,您仍然可以使用"module": "system"进行编译,但按其类型定义中的方式导入validate.js

import validate from 'validate.js';

这样就不需要对 any 进行任何转换,TypeScript 将生成必要的访问代码来访问 default 属性,但缺点是在 Node 中以这种方式导入时根本无法工作。


谢谢!我最终使用了validate.default选项。像你给出的最后一个选项一样导入它会很好,但不幸的是相同的代码需要在浏览器和节点中运行。 - Nitzan Tomer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接