将lodash引入Angular2+TypeScript应用程序

301

我试图导入lodash模块,但一直遇到困难。我使用npm+gulp设置了我的项目,但仍然无法成功。我尝试过常规的lodash,也尝试过lodash-es。

lodash npm包:(在包的根文件夹中有一个index.js文件)

import * as _ from 'lodash';    

结果为:

error TS2307: Cannot find module 'lodash'.

lodash-es npm包:(在包根文件夹的lodash.js中有一个默认导出)

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

结果为:

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

无论是gulp任务还是WebStorm都报告了同样的问题。

有趣的事实是,这不会返回错误:

import 'lodash-es/lodash';

......但是当然没有“_”......

我的tsconfig.json文件:

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

我的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']);

如果我理解正确的话,我的tsconfig中的moduleResolution:'node'应该将import语句指向node_modules文件夹,这里安装了lodash和lodash-es。我也试过很多不同的导入方式:绝对路径、相对路径,但似乎都不起作用。有什么想法吗?

如果需要,我可以提供一个小的zip文件来说明问题。


2
我也遇到了这个问题。lodash库没有以模块化格式包含TypeScript定义,因此导入语句无法正常工作。现在唯一的解决方法似乎是在index.html文件中创建一个脚本引用lodash,然后在你的TypeScript文件中引用lodash.d.ts。希望这个问题能够很快得到解决。如果有其他解决方法,我很想听听。 - brando
1
压缩文件会很好。但是看起来你没有使用任何模块加载器(如jspm或webpack)?你是通过脚本标签加载Angular的吗?最好也发布一下HTML代码。我建议你使用webpack作为模块加载器,这里有一个例子-> https://github.com/jhades/angular2-library-example/tree/master/examples/webpack 这是一个最小化的入门示例-> https://github.com/jhades/ng2-webpack-minimal - Angular University
请查看此链接:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/4889 - brando
1
我最终只是将这个添加到我的邮件ts文件中:/// <reference path="../typings/tsd.d.ts" /> - Davy
截至今天,以上内容均不起作用。我正在使用angular.2.4.4堆栈。 - user1969453
这个回答解决了你的问题吗?在Angular中正确导入和使用lodash的方法 - Anand Raja
23个回答

504

以下是截至Typescript 2.0的操作方法: (tsd和typings已被弃用,推荐使用以下方法):

$ npm install --save lodash

# This is the new bit here: 
$ npm install --save-dev @types/lodash

然后,在你的 .ts 文件中:

要么:

import * as _ from "lodash";

或者(如@Naitik所建议的):

import _ from "lodash";

我不确定它们有什么区别。我们使用并倾向于第一种语法。然而,有些人报告说第一种语法对他们不起作用,还有人评论说后面的语法与懒加载的webpack模块不兼容。您的情况可能会有所不同。

2017年2月27日编辑:

根据@Koert的说法,在Typescript 2.2.1、lodash 4.17.4和@types/lodash 4.14.53下,import * as _ from "lodash";是唯一可行的语法。他表示,其他建议的导入语法会出现“没有默认导出”的错误。


7
我可以确认,在使用 TypeScript 2.0.3 版本时,这个方法是有效的。实际上,使用 @types npm 包替代 typings 更加简洁。 - Adrian Moisa
8
import * as _ from "lodash"; 对我来说不起作用,但 import _ from "lodash"; 可以。 - Gabe O'Leary
5
警告:我发现import _ from "lodash"这种语法与Webpack懒加载模块不兼容。我不确定原因,还没有进行详细的调查。 - Tom Makin
6
在2.0版本中,"import _ from "lodash";"不能再使用,应该改为"import * as _ from "lodash";"。请注意,这个修改并没有改变原意,只是更加通俗易懂地表达了同样的意思。 - Roger Far
7
这应该只在开发中使用,而不是在生产中使用,所以请使用save-dev:npm install --save-dev @types/lodash如果您遇到奇怪的问题和错误,请尝试以下操作:npm install --save-dev @types/lodash@4.14.50 - leetheguy
显示剩余14条评论

70

2016年9月26日更新:

正如@Taytay所述,与几个月前我们使用的'typings'安装不同,现在我们可以使用以下方式:

npm install --save @types/lodash

以下是支持该答案的一些额外参考资料:

如果仍在使用typings安装,请参阅下面(其他人的)关于“--ambient”和“--global”的评论。

另外,在新的快速入门中,配置不再在index.html中;如果使用SystemJS,则现在在systemjs.config.ts中。

原始答案:

在我的Mac上(按照快速入门的说明安装Angular 2后),这个方法可行:

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

你会发现有各种文件受到影响,例如:
  • /typings/main.d.ts
  • /typings.json
  • /package.json
Angular 2 Quickstart使用System.js,因此我在index.html的配置中添加了'map',如下所示:
System.config({
    packages: {
      app: {
        format: 'register',
        defaultExtension: 'js'
      }
    },
    map: {
      lodash: 'node_modules/lodash/lodash.js'
    }
  });

然后在我的.ts代码中,我能够做到:

import _ from 'lodash';

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

2016年中期的编辑:

正如@tibbus所提到的,在某些情况下,您需要:

import * as _ from 'lodash';

如果从angular2-seed开始,并且不想每次都导入,可以跳过映射和导入步骤,只需在tools/config/project.config.ts中取消注释lodash行。
为了让我的测试与lodash一起正常工作,我还需要在karma.conf.js的文件数组中添加一行。
'node_modules/lodash/lodash.js',

1
@zack你有没有在System.config中漏掉了map: { lodash:'node_modules/lodash/lodash.js' } - xwb1989
5
对我来说,只有使用 import * as _ from 'lodash'; 才有效。 - Tiberiu Popescu
--ambient参数是什么作用? - smartmouse
1
为什么我们需要写 import * as _ from 'lodash' 而不是 import _ from 'lodash' - smartmouse
2
@smartmouse --ambient--global 的前身。后者在 1.x 版本及以后的版本中使用。不过,我认为最新的 lodash 4.x 不会像全局模块那样编译。 - demisx
显示剩余5条评论

27

首先要做的事

npm install --save lodash

npm install -D @types/lodash

加载完整的lodash库

//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)

或者:仅加载我们将要使用的函数

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


更新 - 2017年3月

我目前正在使用ES6模块,最近我能够这样使用lodash

// 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)
...

或者导入特定的lodash功能:

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

注意 - 语法上的区别是* as在本例中不是必须的。


参考:

enter image description here

祝你好运。


无法在目标为 ECMAScript 2015 模块时使用导入赋值。 - Toolkit
@Toolkit。感谢您指出这一点。我已经更新了答案。请检查此解决方案是否有效,并做出相应的标记。 - Aakash
3
"allowSyntheticDefaultImports": false时,从'lodash/debounce'导入debounce会产生错误TS1192: Module node_modules/@types/lodash/debounce has no default export。您需要更改此设置或使用正确的导入方式以解决此问题。 - kross
@kross 我刚刚执行了 npm i --save @types/lodash 命令,并查看了 @types/lodash 文件夹,发现了 debounce.d.ts 文件,因此应该可以工作。你可以在这里查看有关 tsconfig.json 的更多信息:https://www.typescriptlang.org/docs/handbook/tsconfig-json.html。我还在答案中包含了一个快照。祝好运... - Aakash
1
我坚持我的先前评论。目前在类型文件中没有默认导出,因此在allowSyntheticDefaultImports为false时无法工作。 - kross
1
@kross 还要注意,在您的 tsconfig.json 文件中添加 "allowSyntheticDefaultImports": true 编译器选项可能是必要的,以避免任何错误。 - Aakash

23

步骤1:修改package.json文件,将lodash包添加到依赖项中。

  "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"  }

步骤2:我在我的Angular2应用程序中使用SystemJs模块加载器。因此,我将修改systemjs.config.js文件以映射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);

第三步:现在执行npm install命令。

第四步:在您的文件中使用lodash。

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

1
你的解决方案如何处理TypeScript类型定义文件呢? npm的lodash包似乎没有包含.d.ts文件。 - Vitali Kniazeu

14

自Typescript 2.0起,@types npm模块用于导入类型定义。

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

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

现在由于这个问题已经得到了答复,我将介绍如何有效地导入lodash

导入整个库的失败安全方式(在main.ts中)

import 'lodash';

这是新内容:

使用您需要的函数实现更轻量级的lodash

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

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

PS:上述文章是一篇有关如何提高构建时间和减小应用程序大小的有趣阅读材料。


1
对于TSC来说,这很棒,但它会给捆绑器带来其他问题。你有没有机会通过rollup让它工作?aurelia-cli也有问题:(。Rollup错误:'default'未被node_modules\lodash\kebabCase.js导出Aurelia cli错误:没有此文件或目录,打开'/experimental\au-proj\node_modules\lodash\lodash\kebabCase.js' - Stephen Lautier
7
似乎@types/lodash尚不支持较轻的语法。“错误TS1192:模块'“node_modules/@types/lodash/chain/index”'没有默认导出。”其他模块也会尝试使用更短的“import chain from“lodash/chain””导入方式,以此类推。 - jamsinclair

10

我使用以下命令成功地将 lodash 导入到我的项目中:

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

然后我以以下方式导入它:

import * as _ from 'lodash';

在 systemjs.config.js 文件中,我定义了以下内容:

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


8

我之前在一个Angular2应用程序中遇到了完全相同的问题,但是通过这篇文章解决了它:https://medium.com/@s_eschweiler/using-external-libraries-with-angular-2-87e06db8e5d1#.p6gra5eli

该文章的摘要如下:

  1. 安装库npm install lodash --save
  2. 添加Lodash的TypeScript定义文件tsd install underscore
  3. 包含脚本<script src="node_modules/lodash/index.js"></script>
  4. 配置SystemJSSystem.config({ paths: { lodash: './node_modules/lodash/index.js'
  5. 导入模块import * as _ from ‘lodash’;

希望这对你也有用。


6
tsd现在已经被弃用了,你应该使用typings。 - hhsadiq

7
另一种优雅的解决方案是只获取您需要的内容,而不是导入所有的lodash。
import {forEach,merge} from "lodash";

然后在您的代码中使用它

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

5
这真的有效吗?我尝试过这个方法,但好像没有改变包的大小。 - Cody
1
也许以前不行,但现在可以了。这是最好的树摇了。 - Pian0_M4n
@alexKhymenko,你能发一下错误吗?这与lodash有关吗? - Pian0_M4n
@Pian0_M4n,没有错误,只是没有树摇。它加载整个库而不是forEach和merge方法。 - alexKhymenko
@alexKhymenko 这很奇怪。我使用生产环境和AOT构建没有问题。你可以尝试添加类型吗?npm i --save @types/lodash?虽然我不使用它们,但这可能会解决你的问题。 - Pian0_M4n
显示剩余5条评论

4

如果其他人遇到此问题,且由于“重复标识符”问题而无法使用上述任何解决方案,请运行以下命令:

npm install typings --global

使用较旧的typings版本可能会出现问题,会出现大量“Duplicate identifier”错误。另外,据我所知,您不再需要使用--ambient

因此,一旦typings更新完毕,这个工作应该就可以了(使用Angular 2快速入门指南)。

运行:

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

首先,在systemjs.config.js中添加以下内容:

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

现在您可以在任何文件中使用以下代码:import * as _ from 'lodash';

如果您仍然遇到问题,请删除您的 typings 文件夹并运行 npm install


4
请注意,npm install --save会在生产代码中引入您的应用程序所需的所有依赖项。
至于 "typings",它仅适用于 TypeScript,最终被转换为 JavaScript。因此,您可能不希望在生产代码中拥有它们。我建议将其放在项目的devDependencies中,方法是使用以下命令:
npm install --save-dev @types/lodash

或者
npm install -D @types/lodash

(参见 Akash 的帖子作为示例)。顺便说一下,这是在 ng2 教程中所做的方式。

另外,您可以将 package.json 设计成以下形式:

{
    "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"
    }
}

小提示

npm 的好处在于你只需要简单地执行 npm install --save 或者 --save-dev,如果你不确定所需依赖的最新版本,它会自动为你设置在 package.json 中以供后续使用。


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