I'm having trouble using Lodash with typescript when I'm trying to extend lodash with my custom mixins.
My unsuccessful attempt:
Lets say I add a new function to lodash using mixins as follows:
//lodashMixins.ts
import * as _ from "lodash";
_.mixin({
swap
});
function swap(array: Array<any>, index1: number, index2: number) {
let temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
return array;
}
The function swap
is not available on _
if I import _ from "lodash";
in other files.
Partially successful attempt:
Then I looked for help, and people suggested to extend
_.LoDashStatic
and then export the _
as the new extended interface
.
Then I did following:
//lodashMixins.ts
import * as _ from "lodash";
interface LodashExtended extends _.LoDashStatic {
swap(array: Array<any>, index1: number, index2: number): Array<any>;
}
_.mixin({
swap
});
function swap(array: Array<any>, index1: number, index2: number) {
let temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
return array;
}
export default _ as LodashExtended;
And using the new mixed-in as following:
//otherFile.ts
import _ from "./lodashMixins";
function someFn(){
var array = [1,2,3,4]
_.swap(array, 1, 2);
}
Now this works, but there are two issues:
swap
function is not working with lodash's chained syntax (neither with explicit chaining nor with implicit chaining).which means, that typescript gets angry if I do any of the following:
//otherFile.ts
import _ from "./lodashMixins";
function someFn(){
var cantDothis = _.chain([1,2,3,4]).map(x=>x*x).swap(1,2).value();
//[ts] Property 'swap' does not exist on type 'LoDashExplicitWrapper<number[]>'.
var neitherThis = _([1,2,3,4]).map(x=>x*x).swap(1,2).value();
//[ts] Property 'swap' does not exist on type 'LoDashImplicitWrapper<number[]>'.
}
import _ from "./lodashMixins";
instead of standard import _ from "lodash";
.Someone please come up with an elegant solution that provides typescript type support while chaining without any code smell or ugliness.. Thanks. :)
May be John-David Dalton can help.
You are looking for module augmentation. You can extend interfaces in existing modules by redefining them and adding extra methods. In this case you should augment LoDashStatic
for static usage and LoDashExplicitWrapper
for chain usage. When you use the module, you can first import lodash
and then import the module containing swap
for its side effects (the side effect of adding the method to lodash
)
// swap.ts
import * as _ from "lodash";
declare module "lodash" {
interface LoDashStatic {
swap<TValue>(array: Array<TValue>, index1: number, index2: number): TValue[];
}
interface LoDashExplicitWrapper<TValue> {
swap(index1: number, index2: number): LoDashExplicitWrapper<TValue>;
}
}
_.mixin({
swap
});
function swap(array: Array<any>, index1: number, index2: number) {
let temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
return array;
}
//usage
import * as _ from "lodash";
import "./swap"
console.log(_.chain([1,2,3,4]).map(x=>x*x).swap(1,2).map(x=> x * 2).value());
var array = [1,2,3,4]
console.log( _.swap(array, 1, 2));
You can read more about module augmentation here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With