I have an exported class
in my working Angular2 app using ES6 module:
//File = init.todos.ts
export class Init {
load() {
...
}
}
I'm importing this class from another component via :
//File = todo.service.ts
import { Init } from './init.todos'
It works as expected.
However if I change the loading mechanism to commonjs :
//File = init.todos.ts
export class Init {
load() {
...
}
}
module.exports.Init = Init;
Requiring it:
//File = todo.service.ts
var Init = require("./init.todos");
— I get those errors :
...myApp/src/app/todo.service.ts (4,13): Cannot find name 'require'.) ...myApp/src/app/todo.service.ts (12,14): Property 'load' does not exist on type 'TodoService'.)
Question:
How can I also load commonjs modules using require
?
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"
]
}
}
Here are the config files :
tslint.json
tsconfig.json
package.json
angular-cli.json
webpack.config.js
I have an exported class
in my working Angular2 app using ES6 module:
//File = init.todos.ts
export class Init {
load() {
...
}
}
I'm importing this class from another component via :
//File = todo.service.ts
import { Init } from './init.todos'
It works as expected.
However if I change the loading mechanism to commonjs :
//File = init.todos.ts
export class Init {
load() {
...
}
}
module.exports.Init = Init;
Requiring it:
//File = todo.service.ts
var Init = require("./init.todos");
— I get those errors :
...myApp/src/app/todo.service.ts (4,13): Cannot find name 'require'.) ...myApp/src/app/todo.service.ts (12,14): Property 'load' does not exist on type 'TodoService'.)
Question:
How can I also load commonjs modules using require
?
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"
]
}
}
Here are the config files :
tslint.json
tsconfig.json
package.json
angular-cli.json
webpack.config.js
Share Improve this question edited Mar 15, 2017 at 15:54 Royi Namir asked Mar 15, 2017 at 15:47 Royi NamirRoyi Namir 149k144 gold badges491 silver badges829 bronze badges 10 | Show 5 more comments3 Answers
Reset to default 9Since version 1.5, Typescript has adopted the ES6 style of imports.
You can keep your code "as is"
//File = init.todos.ts
export class Init {
load() {
...
}
}
//File = todo.service.ts
import { Init } from './init.todos'
By moving the property module
in tsconfig.json
to commonjs
, the transpiler will generate commonjs compatible javascript which will allow you to benefit from, and contribute to, the full nodeJS ecosystem.
"compileOptions": {
...
"module": "commonjs"
...
}
If you wish to import an existing NodeJS module in your typescript code, a few things may happen
the module ships with embedded Typescript Definition Files (there is a "typings" entry in "package.json"). In that case, import the module using the ES6 syntax and you are good to go (
import * as blah from 'blah'
). immutable.js is a good example of such a librarythe module does not ship with Definition files but there is one available on DefinitelyTyped, simply
- run
npm install @types/blah
to get the definitions in your project - and import the module as usual:
import * as blah from 'blah'
- run
the module does not have a definition file
- you can craft one, simply add it to your project after naming it
blah.d.ts
. DefinitelyTyped has a guide on this - you can decide to go without typings, simply use NodeJS require()
const blah = require('blah')
, andblah
will have typeany
(which really means thatblah
opted out of typing)
- you can craft one, simply add it to your project after naming it
(for sake of completeness, I could add the allowJS compiler option available since 1.8, but that is a whole subject in itself)
TypeScript is ES6 compliant. Use ES6 module loading syntax within your TypeScript source files:
import { SomeType } from './some.module';
When TypeScript compiles to regular JavaScript, you can target a module system of your choosing:
"compileOptions": {
"module": "commonjs" (or system, umd, amd)
}
Whatever target module system you choose, you need to ensure that you include the necessary scripts and configuration to load the module. i.e. SystemJS, RequireJS, etc.
As an exercise, try targeting different module loaders, and inspect the .js file - you'll see what I mean.
the problem of your question actually is not the require(...) method.it is that you reference error Init.I think you want to lazy load modules via require.but you load class that contains an instance method load
(it is not a class method,if you want you must declaring it as static
).so you must create an instance before you use it.by default,require(...) return any
declare function require(id: string): any;
if you want typescript infer type correctly you must declare require() return type,e.g:let foo:typeof Foo = require('foo')
.I found that the ts-jest
test pass when module
is anything except system
because it is lazy loading,not execute test definition immediately,so I'm sure the problem is not the module. here is my test code:
Test
//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");
});
"module": "system"
. There's no require function in SystemJS. – Estus Flask Commented Mar 15, 2017 at 15:56module.exports
but I still should import it via es6 syntax ? – Royi Namir Commented Mar 15, 2017 at 16:00const x = require('blah')
, you will be using NodeJS/CommonJS require and "lose" typing sincex
will be mapped to any. This may be useful to import JS librairies which are not typed though – Bruno Grieder Commented Mar 15, 2017 at 16:02