Javascript 打字稿2—;使用"ES6 import& ;;要求

Javascript 打字稿2—;使用"ES6 import& ;;要求,javascript,angular,typescript,module,webpack,Javascript,Angular,Typescript,Module,Webpack,我在使用ES6模块的Angular2应用程序中导出了一个类: //File = init.todos.ts export class Init { load() { ... } } 我正在通过以下方式从另一个组件导入此类: //File = todo.service.ts import { Init } from './init.todos' 它按预期工作 但是,如果我将加载机制更改为commonjs: //File = init.todos.ts export

我在使用ES6模块的Angular2应用程序中导出了一个

//File = init.todos.ts

export class Init {
   load() {
      ...
    }
}
我正在通过以下方式从另一个组件导入此类:

//File = todo.service.ts

import { Init } from './init.todos'
它按预期工作

但是,如果我将加载机制更改为commonjs:

//File = init.todos.ts
export class Init {
    load() {
       ...
    }
}
 module.exports.Init = Init;
要求:

//File = todo.service.ts
var  Init = require("./init.todos");
-我发现这些错误:

…myApp/src/app/todo.service.ts (4,13):找不到名称“require”。) …myApp/src/app/todo.service.ts(12,14): 类型“TodoService”上不存在属性“load”。)

问题:

如何使用
require
加载commonjs模块

Tsconfig.json:

{
    "compileOnSave": false,
    "compilerOptions": {
        "outDir": "./dist/out-tsc",
        "baseUrl": "src",
        "module": "system",
        "sourceMap": true,
        "declaration": false,
        "moduleResolution": "node",
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "target": "es5",
        "typeRoots": [
            "node_modules/@types"
        ],
        "lib": [
            "es2016",
            "dom"
        ]
    }
}
以下是配置文件:


TypeScript符合ES6标准。在TypeScript源文件中使用ES6模块加载语法:

import  { SomeType } from './some.module';
当TypeScript编译为常规JavaScript时,您可以选择一个模块系统作为目标:

"compileOptions": {
    "module": "commonjs" (or system, umd, amd)
}
无论选择什么目标模块系统,都需要确保包含加载模块所需的脚本和配置。i、 e.系统、需求等

作为练习,尝试针对不同的模块加载程序,并检查.js文件-您将了解我的意思。

因为Typescript采用了ES6风格的导入

您可以保持代码“原样”

通过将
tsconfig.json
中的属性
module
移动到
commonjs
,transpiler将生成与commonjs兼容的javascript,使您能够受益于整个nodeJS生态系统,并为之做出贡献

"compileOptions": {
    ...
    "module": "commonjs"
    ...
}
如果希望在typescript代码中导入现有的NodeJS模块,可能会发生一些事情

  • 该模块附带嵌入式Typescript定义文件(“package.json”中有一个“typings”条目)。在这种情况下,使用ES6语法导入模块就可以了(
    import*as blah from'blah'
    )。是这样一个图书馆的好例子

  • 该模块不附带定义文件,但在上有一个可用的定义文件

    • 运行
      npm install@types/blah
      以获取项目中的定义
    • 并像往常一样导入模块:
      import*作为“blah”中的blah
  • 模块没有定义文件

    • 您可以制作一个,只需在命名为
      blah.d.ts
      后将其添加到您的项目中即可。这件事肯定是打字的
    • 您可以决定不键入,只需使用NodeJS require()
      const blah=require('blah')
      ,而
      blah
      将具有type
      any
      (这实际上意味着
      blah
      选择不键入)

(为了完整起见,我可以添加1.8版以来可用的,但这本身就是一个完整的主题)

您问题的问题实际上不是require(…)方法。问题是您引用了error Init。我认为您希望通过require加载模块。但是您加载了包含实例方法的类
load
(它不是类方法,如果需要,必须将其声明为
static
)。因此,必须在使用它之前创建实例。默认情况下,require(…)返回任何

declare function require(id: string): any;
如果希望typescript正确推断类型,则必须声明require()返回类型,例如:
let foo:typeof foo=require('foo'))
。我发现当
模块
不是
系统
时,
ts jest
测试通过,因为它是延迟加载,不能立即执行测试定义,所以我确定问题不在模块。以下是我的测试代码:

试验
这是因为您有
“module”:“system”
。SystemJS中没有require函数。@estus我已经在tsconfig中了,请将“module”更改为“commonjs”,并保留ES6语法,例如`import{Init}来自“/init.todos”。@BrunoGrieder哦,所以导入的模块将具有
模块.exports
,但我仍然应该通过es6语法导入它?是的。Typescript在不久前(1.5或1.7)采用了es6样式导入。如果您使用
const x=require('blah')
,您将使用NodeJS/CommonJS require和“lose”因为
x
会被映射到任何类型。这对于导入未被键入的JS库可能很有用,虽然我很抱歉,但您的意思是在第二种情况下:“模块没有附带定义文件,但在DefiniteTyped上有一个可用的,很简单”-我可以通过“常规要求”导入它。对吗?(我的意思是肯定我可以通过ES6导入获得它,但关键是d.ts允许ts识别需求,不是吗?)ts不“识别需求”。拥有定义文件的意义在于,JS模块可以像用typescript编写一样使用,因此可以使用typescript导入语法导入,这是ES6导入语法是的,这就是我的意思,它允许TS编译器识别新的
d.TS'ed
关键字。(如果我错了,请纠正我)但是我还是想问一下你提到的第二个例子。即使我添加了我朋友用他的blah库(commonjs)发给我的
blah.d.ts
,Typescript只会在我的代码中包含关于
require('blah')
的静音错误。对吗?我的意思是我必须有另一个模块加载器(browserify/webpack)为了让最终的JS实际引用所需的文件。对吗?是的。你需要一个模块绑定器,如browserify或webpack。使用
require
allowJs
你可能可以避免使用一个,但你失去了打字的好处:-)(最后我开始得到它。)-好的,如果是的话-如果我更改Tconfig中的
模块
,会有什么区别?我的意思是-它首先与TS有什么关系?从我的测试中-TS搜索es6语法并转换它..你知道我的误解在哪里吗?TS与Tconfig的模块设置有什么关系?我的意思是它取决于webpack/browserify到“需要”库(es6导入内置INT除外)。
declare function require(id: string): any;
//for inferer type for typescript
//This leverages the reference-elision optimization,
//so that the module is only loaded when needed.
//so use InitClass as a type will skipped.
import {Init as InitClass} from  "./init.todos";

test("typescript dynamic load supports inferer types", () => {
    let Init: typeof InitClass = require("./init.todos").Init;

    let it = new Init();
    expect(it.load()).toEqual("bar");
});