Unable to import lodash - node.js

I'm new to TypeScript and I'm facing a problem while trying to load lodash.
Here is my code :
///<reference path="../../typings/lodash/lodash.d.ts"/>
///<reference path="../interfaces/IScheduler.ts"/>
import _ = require('lodash');
module MyModule {
export class LeastUsedScheduler implements IScheduler {
/// CODE HERE
}
}
I tried replacing the import line by :
import * as _ from lodash;
In the two cases I get :
"error| Cannot find name 'IScheduler'."
When I remove the import directive it compiles perfectly but _ is undefined at runtime.
I also tried to put the import inside the module without success.
I'm sorry It must be a very dumb question but I can't figure it out.
Thank you
EDIT :
I understood the problem. Referencing the typing for lodash created the variable _ in the scope. That's why it compiles fine without the import line. The problem is referencing the typing does not really import lodash. That's why it fails at runtime.
When I import lodash the compilation fails because lodash is already in the scope.
Thank you for your support.

I'm not 100% about the issue but can you try the following and let me know how it goes?
///<reference path="../../typings/lodash/lodash.d.ts"/>
///<reference path="../interfaces/IScheduler.ts"/>
import _ = require("lodash");
export class LeastUsedScheduler implements IScheduler {
doSomething(){
_.each([],function name(parameter) {
// ...
});
}
}
When compiled it looks like:
var _ = require("lodash");
var LeastUsedScheduler = (function () {
function LeastUsedScheduler() {
}
LeastUsedScheduler.prototype.doSomething = function () {
_.each([], function name(parameter) {
throw new Error("Not implemented yet");
});
};
return LeastUsedScheduler;
})();
exports.LeastUsedScheduler = LeastUsedScheduler;
If you import the module import _ = require("lodash"); but you don't use it, TypeScript will remove the import (I added the doSoemthing method for that reason).
Update: Why it didn't work?
The problem was that the module keyword is used to declare an internal module. At the same time the code was loading an external module. You should avoid mixing internal and external modules. You can learn more about the difference between internal and external modules at http://www.codebelt.com/typescript/typescript-internal-and-external-modules/.
Also, if you use internal modules avoid using the module keyword as it is deprecated and you should use the namespace keyword instead.

Related

sinonjs - stub a library referenced internally as a function using node modules (no require)

I have an external library that is exported as a function, in the Stub documentation it only accepts an input with the first parameter as object and the second parameter as method , so how could I stub a library that is exported as a function in a Node ES Modules environment (without Commonjs)?
(In my specific case, I had used a library that use the internet to work, and I wanted to test derivated functions without accessing the internet, so I want to stub the external function library)
Attempts:
I couldn't use solutions like proxyquire as it is a solution based on require and module cache deletion, which are not supported within Node's ES modules.
I don't want to use proxyquire-universal because it simulates the operation of require in normal ES, and it's just a function in the whole project that I wanted to test, I was looking for a simpler solution
Changing the import mode doesn't work as it's not recompiled like in babel, so even if I import as import * as obj from 'lib' only the function name is changed
I had this error environment with 3 files:
An external library called "sum" for example, which I don't want to change, exported as follows:
External Library: externalSum.js
module.exports = function sum(a, b){
console.log(">>>>> running without stub <<<<<")
return a + b
}
This library used in the middle of a project file called mathProblems
Internal File: mathProblems.js
import sum from 'externalSum'
export function sumMore1(a) {
return sum(a, 1);
}
And I have a test file
Internal File: spec.js
import sinon from 'sinon'
import assert from 'assert'
import sumObj from 'externalSum'
import { sumMore1 } from '../mathProblems.js'
describe('sumMore1 is working', () => {
it('sumMore1 test', () => {
const sum_stub = sinon.stub(sumObj) // NOT STUBBING
sum_stub.withArgs(1, 1).returns(2) // NOT STUBBING
const result = sumMore1(1)
assert.strictEqual(result, 2)
});
});
I didn't find this solution anywhere on the internet, i found some solutions that work for node with request or babilon, but not for my case using ES Modules:
https://github.com/sinonjs/sinon/issues/562
https://minaluke.medium.com/how-to-stub-spy-a-default-exported-function-a2dc1b580a6b
So I wanted to register the solution in case anyone needs it.
To solve this, create a new file, which can be allocated anywhere in the project, in this case I will call it sumImport.js:
Internal File: sumImport.js
import sum from 'externalSum';
// export as object
export default {
sum
}
The object needs to be called inside the created function I want to test, and changed the import way:
Internal File: mathProblems.js
import sumObj from './sumImport.js';
export function sumMore1(a) {
const { sum } = sumObj;
return sum(a, 1);
}
And I finally managed to import as an object in the test:
Internal File: spec.js
import sinon from 'sinon'
import assert from 'assert'
import sumObj from '../sumImport.js'
import { sumMore1 } from '../mathProblems.js'
describe('sumMore1 is working', () => {
it('sumMore1 test', () => {
const sum_stub = sinon.stub(sumObj, "sum") // STUBBED
sum_stub.withArgs(1, 1).returns(2) // STUBBED
const result = sumMore1(1)
assert.strictEqual(result, 2)
});
});
I hope it helps someone and if someone else has some better solutions I would also be grateful!

What does Babel do to let me use any name to import a node module that exports a function

An example will make my question clearer, say I want to import debug module to my vuejs codes
Debug module export createDebug function like this,
module.exports = require('./browser.js');
...
exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
function createDebug(namespace) { ... }
When I use import to import debug module, I can give it any name I want, like
import debug from 'debug' // or any name I want, e.g
import debugjs from 'debug'
I understand if export default anonymous function I can then import it with any name I want, but this is not the case here.
So why can I use any name to import it?
---------------- update -----------------
One takeaway from the answer is that import "any name" work for both default export anonymous function and named function.
but this is not the case here.
It kind of is. You are trying to import a module that has no ES6 exports. You are trying to import a CommonJS module. So Babel has to make a decision how to handle that case.
There are two common ways to export something from a CommonJS module:
Assign a property to exports (or module.expoets), for example exports.answer = 42;
Overwrite the value of module.exports, e.g. module.exports = 42;.
In the second case you end up exporting only a single value from the module. That's basically what a default export is (since there can only be one) and that's what you are doing in your code.
So in other words, when importing a CommonJS module via ES6 import statements, then the value of module.exports is used as the default export value.
We can confirm that by looking at how Babel converts the code:
// import foo from 'bar'; becomes
var _bar = require('bar');
var _bar2 = _interopRequireDefault(_bar);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
// ^^^^^^^^^^^^^^^^
}

How do you write a node module using typescript?

So, the general answer for the other question (How do you import a module using typescript) is:
1) Create a blah.d.ts definition file.
2) Use:
/// <reference path="./defs/foo/foo.d.ts"/>
import foo = require("foo");
Critically, you need both the files foo.d.ts and a foo.js somewhere in your node_modules to load; and the NAME foo must exactly match for both. Now...
The question I would like to have answered is how to you write a typescript module that you can import that way?
Lets say I have a module like this:
- xq/
- xq/defs/Q.d.ts
- xq/index.ts
- xq/base.ts
- xq/thing.ts
I want to export the module 'xq' with the classes 'Base' from base.ts, and 'Thing' from thing.ts.
If this was a node module in javascript, my index.ts would look something like:
var base = require('./base');
var thing = require('./thing');
module.exports = {
Base: base.Base,
Thing: thing.Thing
};
Let's try using a similar typescript file:
import base = require('./base');
export module xq {
export var base = base.Base;
}
Invoke it:
tsc base.ts index.ts things.ts ... --sourcemap --declaration --target ES3
--module commonjs --outDir dist/xq
What happens? Well, we get our base.d.ts:
export declare class Base<T> {
...
}
and the thrillingly unuseful index.d.ts:
export declare module xq {
var Base: any; // No type hinting! Great. :(
}
and completely invalid javascript that doesn't event import the module:
(function (xq) {
xq.base = xq.base.Base;
})(exports.xq || (exports.xq = {}));
var xq = exports.xq;
I've tried a pile of variations on the theme and the only thing I can get to work is:
declare var require;
var base = require('./base');
export module xq {
export var base = base.Base;
}
...but that obviously completely destroys the type checker.
So.
Typescript is great, but this module stuff completely sucks.
1) Is it possible to do with the built in definition generator (I'm dubious)
2) How do you do it by hand? I've seen import statements in .d.ts files, which I presume means someone has figured out how to do this; how do those work? How do you do the typescript for a module that has a declaration with an import statement in it?
(eg. I suspect the correct way to do a module declaration is:
/// <reference path="base.d.ts" />
declare module "xq" {
import base = require('./base');
module xq {
// Some how export the symbol base.Base as Base here
}
export = xq;
}
...but I have no idea what the typescript to go along that would be).
For JavaScript :
var base = require('./base');
var thing = require('./thing');
module.exports = {
Base: base.Base,
Thing: thing.Thing
};
TypeScript :
import base = require('./base');
import thing = require('./thing');
var toExport = {
Base: base.Base,
Thing: thing.Thing
};
export = toExport;
Or even this typescript:
import base = require('./base');
import thing = require('./thing');
export var Base = base.Base;
export var Thing = thing.Thin;
Typescript has really improved since this question was asked. In recent versions of Typescript, the language has become a much more strict superset of Javascript.
The right way to import/export modules is now the new ES6 Module syntax:
myLib.ts
export function myFunc() {
return 'test'
}
package.json
{
"name": "myLib",
"main": "myLib.js",
"typings": "myLib.d.ts"
}
Dependents can then import your module using the new ES6 syntax:
dependent.ts
import { myFunc } from 'myLib'
console.log(myFunc())
// => 'test'
For a full example of a node module written in Typescript, please check out this boilerplate:
https://github.com/bitjson/typescript-starter/

How to export and import type definitions?

I've been using TypeScript for a while and the module system continues to be a mystery to me.
I have this type definition file (appComponents.d.ts):
/// <reference path="./authentication/API.d.ts"/>
import express = require('express');
declare module appComponents {
export interface IComponents {
application: express.Application;
authenticationService: MyApp.IAuthenticationService;
// and so on ...
}
}
and this file (index.ts):
/// <reference path="./appComponents.d.ts"/>
import express = require('express');
import mssql = require('mssql');
function initComponents(): appComponents.IComponents {
// Components initialized here ...
}
Two questions:
Why do I have to use
import express = require('express');
instead of
/// <reference path="./path/to/definitely-typed/express/express.d.ts"/>
to avoid error TS2095: Could not find symbol 'express'.? After all, this is just a type definition file that generates no JavaScript depending on the types in another type definition file that also generates no JavaScript.
Why does index.ts cause error TS2095: Could not find symbol 'appComponents'.? And when I do this instead:
import appComponents = require('./appComponents');
why does it cause error TS2094: The property 'IComponents' does not exist on the value of type 'appComponents'.?
Using TypeScript 0.9.7.0.
) Why do I have to use
import express = require('express');
instead of
/// <reference path="./path/to/definitely-typed/express/express.d.ts"/>
Actually you need to use both:
/// <reference path="./path/to/definitely-typed/express/express.d.ts"/>
import express = require('express');
You probably have the reference in API.d.ts or simply have express.d.ts included in your visual studio project somewhere.
How it works : https://github.com/borisyankov/DefinitelyTyped/blob/master/express/express.d.ts#L15 contains declare module "express" { This tells typescript what to give (everything with export in this file : https://github.com/borisyankov/DefinitelyTyped/blob/master/express/express.d.ts when someone does import / require i.e import express = require('express') These are known as external modules in typescript and can be amd / commonjs
Why does index.ts cause error TS2095: Could not find symbol 'appComponents'
Because you are declaring an internal module and trying to import it as an external module.
PS: video about external / internal modules : http://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1
UPDATE
You said that one of my modules in the question is an internal module:
Just FYI: declare module appComponents { makes appComponents an internal module. You should do declare module "appComponents" { if you want to declare an external module and use import appComponents = require('appComponents'); But don't. Its not what you want.
Why does index.ts cause error TS2095: Could not find symbol 'appComponents'.?
Because appComponents.d.ts does an import it too became an external module. You should move declare module appComponents { etc. to its own file free of external modules and then use ///<reference
Here's what solved my problem (#2):
Don't create .d.ts files as a way of separating interface and implementation of classes. Instead, define interfaces in .ts files. When a class and the interface it implements are in different files, require the interface module from the class module. Do this also for interfaces that are not to be implemented by a class, i.e. interfaces used for strong typing of variables.
Example:
// IAppComponents.ts
/// <reference path="../DefinitelyTyped/express/express.d.ts"/>
import express = require('express');
import IAuthenticationService = require('./services/IAuthenticationService')
interface IAppComponents {
application: express.Application;
authenticationService: IAuthenticationService;
}
export = IAppComponents;
// IAuthenticationService.ts
import ILoginCallback = require('./ILoginCallback');
import ILogoutCallback = require('./ILogoutCallback');
interface IAuthenticationService {
login(user: string, pass: string, callback: ILoginCallback) void;
logout(sessionToken: string, callback: ILogoutCallback): void;
}
export = IAuthenticationService;
// AuthenticationService.ts
import IAuthenticationService = require('./IAuthenticationService');
import ILoginCallback = require('./ILoginCallback');
import ILogoutCallback = require('./ILogoutCallback');
// We can't import this, because it's a js module with no matching type definition.
var mssql = require('mssql');
class AuthenticationService implements IAuthenticationService {
login(user: string, pass: string, callback: ILoginCallback): void {
// Implementation goes here ...
}
logout(sessionToken: string, callback: ILogoutCallback): void {
// Implementation goes here ...
}
}
export = AuthenticationService;
This approach works, with one tiny caveat: The TypeScript compiler generates .js files for each .ts (but not .d.ts) file, even if the .ts file contains only interfaces, resulting in empty .js files being generated. I can live with that for now, but I hope the TypeScript team does something about it one day.

Typescript import mechanism in Nodejs

I'm totally stuck right now. Using Nodejs.
Having the following setup:
Compile -target ES5 --module commonjs
/def/mongoose.d.ts:
export = M;
declare module M {
export class Collection {
name:string;
}
}
/model/users.ts:
///<reference path='..\def/mongoose.d.ts' />
export var foo:M.Collection;
Error: /model/users.ts(21,16): error TS2095: Could not find symbol 'M'.
Made it as simple as possible. I tried a lot but did not managed to access the class in the mongoose.d.ts
Instead of using a reference comment, you should import the module:
import M = require('./def/mongoose');
export var foo: M.Collection;
Usually, you would give the .d.ts file the same name (and location) as the .js file so the import statement would also load it at runtime.

Resources