[javascript] Importing lodash into angular2 + typescript application

I am having a hard time trying to get the lodash modules imported. I've setup my project using npm+gulp, and keep hitting the same wall. I've tried the regular lodash, but also lodash-es.

The lodash npm package: (has an index.js file in the package root folder)

import * as _ from 'lodash';    

Results in:

error TS2307: Cannot find module 'lodash'.

The lodash-es npm package: (has a defaut export in lodash.js i the package root folder)

import * as _ from 'lodash-es/lodash';

Results in:

error TS2307: Cannot find module 'lodash-es'.   

Both the gulp task and webstorm report the same issue.

Funny fact, this returns no error:

import 'lodash-es/lodash';

... but of course there is no "_" ...

My tsconfig.json file:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
    "node_modules"
  ]
}

My gulpfile.js:

var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    uglify = require('gulp-uglify'),
    sourcemaps = require('gulp-sourcemaps'),
    tsPath = 'app/**/*.ts';

gulp.task('ts', function () {
    var tscConfig = require('./tsconfig.json');

    gulp.src([tsPath])
        .pipe(sourcemaps.init())
        .pipe(ts(tscConfig.compilerOptions))
        .pipe(sourcemaps.write('./../js'));
});

gulp.task('watch', function() {
    gulp.watch([tsPath], ['ts']);
});

gulp.task('default', ['ts', 'watch']);

If i understand correctly, moduleResolution:'node' in my tsconfig should point the import statements to the node_modules folder, where lodash and lodash-es are installed. I've also tried lots of different ways to import: absolute paths, relative paths, but nothing seems to work. Any ideas?

If necessary i can provide a small zip file to illustrate the problem.

This question is related to javascript angular typescript lodash es6-module-loader

The answer is


I'm on Angular 4.0.0 using the preboot/angular-webpack, and had to go a slightly different route.

The solution provided by @Taytay mostly worked for me:

npm install --save lodash
npm install --save @types/lodash

and importing the functions into a given .component.ts file using:

import * as _ from "lodash";

This works because there's no "default" exported class. The difference in mine was I needed to find the way that was provided to load in 3rd party libraries: vendor.ts which sat at:

src/vendor.ts

My vendor.ts file looks like this now:

import '@angular/platform-browser';
import '@angular/platform-browser-dynamic';
import '@angular/core';
import '@angular/common';
import '@angular/http';
import '@angular/router';

import 'rxjs';
import 'lodash';

// Other vendors for example jQuery, Lodash or Bootstrap
// You can import js, ts, css, sass, ...

I had exactly the same problem, but in an Angular2 app, and this article just solve it: https://medium.com/@s_eschweiler/using-external-libraries-with-angular-2-87e06db8e5d1#.p6gra5eli

Summary of the article:

  1. Installing the Library npm install lodash --save
  2. Add TypeScript Definitions for Lodash tsd install underscore
  3. Including Script <script src="node_modules/lodash/index.js"></script>
  4. Configuring SystemJS System.config({ paths: { lodash: './node_modules/lodash/index.js'
  5. Importing Module import * as _ from ‘lodash’;

I hope it can be useful for your case too


Partial import from lodash should work in angular 4.1.x using following notation:

let assign = require('lodash/assign');

Or use 'lodash-es' and import in module:

import { assign } from 'lodash-es';

You can also go ahead and import via good old require, ie:

const _get: any = require('lodash.get');

This is the only thing that worked for us. Of course, make sure any require() calls come after imports.


npm install --save @types/lodash

https://www.npmjs.com/package/@types/lodash


If anyone else runs into this issue and none of the above solutions work due to "Duplicate identifier" issues, run this:

npm install typings --global

With older versions of typings things mess up and you'll get a bunch of "Duplicate identifier" issues. Also you don't need to use --ambient anymore as far as I could tell.

So once typings is up to date, this should work (using the Angular 2 quickstart).

Run:

npm install lodash --save 
typings install lodash --save

First, add this to systemjs.config.js:

'lodash':                     'node_modules/lodash/lodash.js'

Now you can use this in any file: import * as _ from 'lodash';

Delete your typings folder and run npm install if you're still having issues.


Update September 26, 2016:

As @Taytay's answer says, instead of the 'typings' installations that we used a few months ago, we can now use:

npm install --save @types/lodash

Here are some additional references supporting that answer:

If still using the typings installation, see the comments below (by others) regarding '''--ambient''' and '''--global'''.

Also, in the new Quick Start, config is no longer in index.html; it's now in systemjs.config.ts (if using SystemJS).

Original Answer:

This worked on my mac (after installing Angular 2 as per Quick Start):

sudo npm install typings --global
npm install lodash --save 
typings install lodash --ambient --save

You will find various files affected, e.g.

  • /typings/main.d.ts
  • /typings.json
  • /package.json

Angular 2 Quickstart uses System.js, so I added 'map' to the config in index.html as follows:

System.config({
    packages: {
      app: {
        format: 'register',
        defaultExtension: 'js'
      }
    },
    map: {
      lodash: 'node_modules/lodash/lodash.js'
    }
  });

Then in my .ts code I was able to do:

import _ from 'lodash';

console.log('lodash version:', _.VERSION);

Edits from mid-2016:

As @tibbus mentions, in some contexts, you need:

import * as _ from 'lodash';

If starting from angular2-seed, and if you don't want to import every time, you can skip the map and import steps and just uncomment the lodash line in tools/config/project.config.ts.

To get my tests working with lodash, I also had to add a line to the files array in karma.conf.js:

'node_modules/lodash/lodash.js',

I successfully imported lodash in my project with the following commands:

npm install lodash --save
typings install lodash --save

Then i imported it in the following way:

import * as _ from 'lodash';

and in systemjs.config.js i defined this:

map: { 'lodash' : 'node_modules/lodash/lodash.js' }


Maybe it is too strange, but none of the above helped me, first of all, because I had properly installed the lodash (also re-installed via above suggestions).

So long story short the issue was connected with using _.has method from lodash.

I fixed it by simply using JS in operator.


Please note that npm install --save will foster whatever dependency your app requires in production code.
As for "typings", it is only required by TypeScript, which is eventually transpiled in JavaScript. Therefore, you probably do not want to have them in production code. I suggest to put it in your project's devDependencies instead, by using

npm install --save-dev @types/lodash

or

npm install -D @types/lodash

(see Akash post for example). By the way, it's the way it is done in ng2 tuto.

Alternatively, here is how your package.json could look like:

{
    "name": "my-project-name",
    "version": "my-project-version",
    "scripts": {whatever scripts you need: start, lite, ...},
    // here comes the interesting part
    "dependencies": {
       "lodash": "^4.17.2"
    }
    "devDependencies": {
        "@types/lodash": "^4.14.40"
    }
}

just a tip

The nice thing about npm is that you can start by simply do an npm install --save or --save-dev if you are not sure about the latest available version of the dependency you are looking for, and it will automatically set it for you in your package.json for further use.


try >> tsd install lodash --save


I had created typings for lodash-es also, so now you can actually do the following

install

npm install lodash-es -S
npm install @types/lodash-es -D

usage

import kebabCase from "lodash-es/kebabCase";
const wings = kebabCase("chickenWings");

if you use rollup, i suggest using this instead of the lodash as it will be treeshaken properly.


Install via npm.

$ npm install lodash --save

Now, import in the file:

$ import * as _ from 'lodash';

ENV:

Angular CLI: 1.6.6
Node: 6.11.2
OS: darwin x64
Angular: 5.2.2
typescript: 2.4.2
webpack: 3.10.0


if dosen't work after

$ npm install lodash --save 
$ npm install --save-dev @types/lodash

you try this and import lodash

typings install lodash --save

First things first

npm install --save lodash

npm install -D @types/lodash

Load the full lodash library

//some_module_file.ts
// Load the full library...
import * as _ from 'lodash' 
// work with whatever lodash functions we want
_.debounce(...) // this is typesafe (as expected)

OR load only functions we are going to work with

import * as debounce from 'lodash/debounce'
//work with the debounce function directly
debounce(...)   // this too is typesafe (as expected)


UPDATE - March 2017

I'm currently working with ES6 modules, and recently i was able to work with lodash like so:

// the-module.js (IT SHOULD WORK WITH TYPESCRIPT - .ts AS WELL) 
// Load the full library...
import _ from 'lodash' 
// work with whatever lodash functions we want
_.debounce(...) // this is typesafe (as expected)
...

OR import specific lodash functionality:

import debounce from 'lodash/debounce'
//work with the debounce function directly
debounce(...)   // this too is typesafe (as expected)
...

NOTE - the difference being * as is not required in the syntax


References:

enter image description here

Good Luck.


Another elegant solution is to get only what you need, not import all the lodash

import {forEach,merge} from "lodash";

and then use it in your code

forEach({'a':2,'b':3}, (v,k) => {
   console.log(k);
})

I am using ng2 with webpack, not system JS. Steps need for me were:

npm install underscore --save
typings install dt~underscore --global --save

and then in the file I wish to import underscore into:

import * as _ from 'underscore';

  1. Install lodash

sudo npm install typings --global npm install lodash --save typings install lodash --ambient --save

  1. In index.html, add map for lodash:

System.config({ packages: { app: { format: 'register', defaultExtension: 'js' } }, map: { lodash: 'node_modules/lodash/index.js' } });

  1. In .ts code import lodash module

import _ from 'lodash';


Managing types via typings and tsd commands is ultimately deprecated in favor of using npm via npm install @types/lodash.

However, I struggled with "Cannot find module lodash" in import statement for a long time:

import * as _ from 'lodash';

Ultimately I realized Typescript will only load types from node_modules/@types start version 2, and my VsCode Language service was still using 1.8, so the editor was reporting errors.

If you're using VSCode you'll want to include

"typescript.tsdk":  "node_modules/typescript/lib"

in your VSCode settings.json file (for workspace settings) and make sure you have typescript version >= 2.0.0 installed via npm install [email protected] --save-dev

After that my editor wouldn't complain about the import statement.


Step 1: Modify package.json file to include lodash in the dependencies.

  "dependencies": {
"@angular/common":  "2.0.0-rc.1",
"@angular/compiler":  "2.0.0-rc.1",
"@angular/core":  "2.0.0-rc.1",
"@angular/http":  "2.0.0-rc.1",
"@angular/platform-browser":  "2.0.0-rc.1",
"@angular/platform-browser-dynamic":  "2.0.0-rc.1",
"@angular/router":  "2.0.0-rc.1",
"@angular/router-deprecated":  "2.0.0-rc.1",
"@angular/upgrade":  "2.0.0-rc.1",
"systemjs": "0.19.27",
"es6-shim": "^0.35.0",
"reflect-metadata": "^0.1.3",
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"lodash":"^4.12.0",
"angular2-in-memory-web-api": "0.0.7",
"bootstrap": "^3.3.6"  }

Step 2:I am using SystemJs module loader in my angular2 application. So I would be modifying the systemjs.config.js file to map lodash.

(function(global) {

// map tells the System loader where to look for things
var map = {
    'app':                        'app', // 'dist',
    'rxjs':                       'node_modules/rxjs',
    'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
    '@angular':                   'node_modules/@angular',
    'lodash':                    'node_modules/lodash'
};

// packages tells the System loader how to load when no filename and/or no extension
var packages = {
    'app':                        { main: 'main.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { defaultExtension: 'js' },
    'lodash':                    {main:'index.js', defaultExtension:'js'}
};

var packageNames = [
    '@angular/common',
    '@angular/compiler',
    '@angular/core',
    '@angular/http',
    '@angular/platform-browser',
    '@angular/platform-browser-dynamic',
    '@angular/router',
    '@angular/router-deprecated',
    '@angular/testing',
    '@angular/upgrade',
];

// add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function(pkgName) {
    packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});

var config = {
    map: map,
    packages: packages
}

// filterSystemConfig - index.html's chance to modify config before we register it.
if (global.filterSystemConfig) { global.filterSystemConfig(config); }

System.config(config);})(this);

Step 3: Now do npm install

Step 4: To use lodash in your file.

import * as _ from 'lodash';
let firstIndexOfElement=_.findIndex(array,criteria);

Install all thru terminal:

npm install lodash --save
tsd install lodash --save

Add paths in index.html

<script>
    System.config({
        packages: {
            app: {
                format: 'register',
                defaultExtension: 'js'
            }
        },
        paths: {
            lodash: './node_modules/lodash/lodash.js'
        }
    });
    System.import('app/init').then(null, console.error.bind(console));
</script>

Import lodash at the top of the .ts file

import * as _ from 'lodash'

Since Typescript 2.0, @types npm modules are used to import typings.

# Implementation package (required to run)
$ npm install --save lodash

# Typescript Description
$ npm install --save @types/lodash 

Now since this question has been answered I'll go into how to efficiently import lodash

The failsafe way to import the entire library (in main.ts)

import 'lodash';

This is the new bit here:

Implementing a lighter lodash with the functions you require

import chain from "lodash/chain";
import value from "lodash/value";
import map from "lodash/map";
import mixin from "lodash/mixin";
import _ from "lodash/wrapperLodash";

source: https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba#.kg6azugbd

PS: The above article is an interesting read on improving build time and reducing app size


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to angular

error NG6002: Appears in the NgModule.imports of AppModule, but could not be resolved to an NgModule class error TS1086: An accessor cannot be declared in an ambient context in Angular 9 TS1086: An accessor cannot be declared in ambient context @angular/material/index.d.ts' is not a module Why powershell does not run Angular commands? error: This is probably not a problem with npm. There is likely additional logging output above Angular @ViewChild() error: Expected 2 arguments, but got 1 Schema validation failed with the following errors: Data path ".builders['app-shell']" should have required property 'class' Access blocked by CORS policy: Response to preflight request doesn't pass access control check origin 'http://localhost:4200' has been blocked by CORS policy in Angular7

Examples related to typescript

TS1086: An accessor cannot be declared in ambient context Element implicitly has an 'any' type because expression of type 'string' can't be used to index Angular @ViewChild() error: Expected 2 arguments, but got 1 Typescript: No index signature with a parameter of type 'string' was found on type '{ "A": string; } Understanding esModuleInterop in tsconfig file How can I solve the error 'TS2532: Object is possibly 'undefined'? Typescript: Type 'string | undefined' is not assignable to type 'string' Typescript: Type X is missing the following properties from type Y length, pop, push, concat, and 26 more. [2740] Can't perform a React state update on an unmounted component TypeScript and React - children type?

Examples related to lodash

Can't perform a React state update on an unmounted component Angular 4 HttpClient Query Parameters use Lodash to sort array of object by value How to group an array of objects by key Removing object properties with Lodash How to merge two arrays of objects by ID using lodash? Error: EACCES: permission denied Replacing objects in array lodash: mapping array to object Correct way to import lodash

Examples related to es6-module-loader

Importing lodash into angular2 + typescript application "You may need an appropriate loader to handle this file type" with Webpack and Babel