Импорт lodash в Angular 2+ с TypeScript: как правильно установить и использовать
Правильная установка и импорт lodash в Angular + TypeScript
Проблема, с которой вы столкнулись, типична для многих разработчиков, переходящих на TypeScript. Дело в том, что lodash — это CommonJS-модуль, и его импорт в TypeScript-проекте требует особого подхода. Вот пошаговое решение.
Шаг 1: Убедитесь, что установлены все зависимости
npm install lodash
npm install @types/lodash --save-dev
Типы обязательны, иначе TypeScript не сможет проверить типы методов lodash.
Шаг 2: Настройте tsconfig.json
Убедитесь, что у вас включены следующие опции:
{
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true
}
}
esModuleInterop: true— позволяет импортировать CommonJS-модули как ES-модули (решает проблему с default export).allowSyntheticDefaultImports: true— разрешает импорт по умолчанию из модулей без default export.
Шаг 3: Импортируйте lodash правильно
Есть три основных способа импорта, в зависимости от ваших целей:
Вариант 1: Импорт всей библиотеки (не рекомендуется для production)
import * as _ from 'lodash';
// или
import _ from 'lodash'; // работает с esModuleInterop: true
// Использование:
const cloned = _.cloneDeep(data);
const debounced = _.debounce(() => console.log('hi'), 300);
Минус: в итоговый бандл попадёт вся библиотека (~500 КБ), даже если вы используете 5 методов.
Вариант 2: Импорт отдельных функций (рекомендуется для оптимизации)
import cloneDeep from 'lodash/cloneDeep';
import debounce from 'lodash/debounce';
// Использование:
const cloned = cloneDeep(data);
const debounced = debounce(() => console.log('hi'), 300);
Этот способ позволяет tree-shaking'у (в Angular CLI он включен по умолчанию) удалить неиспользуемый код. В бандл попадут только те функции, которые вы импортировали.
Вариант 3: Деструктуризация из корневого модуля (менее эффективно)
import { cloneDeep, debounce } from 'lodash';
Важно: Этот способ часто не срабатывает с tree-shaking, потому что Angular CLI не всегда может корректно обработать такой импорт для CommonJS-модулей. Лучше используйте вариант 2.
Шаг 4: Дополнительная оптимизация — lodash-es
Если вы используете Angular 12+ и хотите максимальную производительность, установите lodash-es (версию lodash в формате ES-модулей):
npm install lodash-es
npm install @types/lodash-es --save-dev
Тогда импорт будет выглядеть так:
import { cloneDeep, debounce } from 'lodash-es';
Это гарантирует, что tree-shaking сработает на 100%, так как lodash-es — это нативные ES-модули.
Проверка работоспособности
После всех настроек ваш компонент должен выглядеть так:
import { Component, OnInit } from '@angular/core';
import cloneDeep from 'lodash/cloneDeep';
@Component({
selector: 'app-my-component',
templateUrl: './my-component.component.html'
})
export class MyComponent implements OnInit {
data: any = { user: { name: 'John' } };
ngOnInit() {
const cloned = cloneDeep(this.data);
console.log(cloned); // { user: { name: 'John' } }
}
}
Что делать, если ошибка остаётся?
- Перезапустите сервер разработки (
ng serve). - Удалите папку
node_modulesи выполнитеnpm installзаново. - Проверьте, что в вашем
angular.jsonнет странных настроек, блокирующих импорт из node_modules. - Если используете Angular 9+, попробуйте добавить
"allowSyntheticDefaultImports": trueвtsconfig.app.json(отдельно для приложения).
Теперь lodash должен работать без ошибок, а ваш бандл останется минимальным за счёт точечных импортов.
<<Альтернативный подход: использование встроенных возможностей Angular и JavaScript
Прежде чем подключать lodash, подумайте: возможно, вы можете обойтись без него? Современный JavaScript и Angular предоставляют многие функции, которые раньше требовали lodash.
Замена cloneDeep
Для глубокого копирования объектов можно использовать JSON-сериализацию (работает только для простых объектов без методов):
const cloned = JSON.parse(JSON.stringify(this.data));
Для более сложных случаев (с датами, Map, Set) используйте structuredClone (доступен в современных браузерах и Node 17+):
const cloned = structuredClone(this.data);
Замена debounce
В Angular для этой цели лучше использовать RxJS:
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
private searchSubject = new Subject();
ngOnInit() {
this.searchSubject.pipe(
debounceTime(300),
distinctUntilChanged()
).subscribe(value => {
console.log('Debounced:', value);
});
}
onInputChange(value: string) {
this.searchSubject.next(value);
}
Это нативный для Angular подход, который лучше интегрируется с экосистемой и не требует дополнительных библиотек.
Когда всё же стоит использовать lodash
- Если вам нужны специфические функции, которых нет в JS (например,
_.merge,_.pickBy,_.chain). - Если код уже активно использует lodash и его замена потребует много времени.
- Если вы работаете с очень глубокими структурами данных, где JSON.parse/JSON.stringify может быть медленным.
В остальных случаях старайтесь минимизировать зависимости — это упростит поддержку и уменьшит размер приложения.