如何在TypeScript中使用lodash.mixin

问题描述 投票:0回答:6

我的团队正在评估将一些文件从 JavaScript 切换到 TypeScript,并且我们在代码中广泛使用了一些自定义 mixin 方法。从一些基本测试来看,虽然我们可以使用 _.mixin 按照规范创建 mixin,但我们无法在不出现编译错误的情况下引用它们。当然,我们可以将这些引用放在定义文件中,但我通常不喜欢修改它。

有什么办法可以实现我们正在寻找的东西,还是我们运气不好?

typescript lodash
6个回答
8
投票

请参阅关于 扩展内置类型 的 TypeScript 文档,我认为这也适用于这里。

_
定义为
var _: _.LoDashStatic
,并且
var
目前不可扩展。

我发现公开扩展的最佳方法是通过

lodash-mixins.ts
脚本定义新的
LoDashMixins
接口(扩展
LoDashStatic
),应用 mixins,并将
_
转换导出到自定义接口。此示例定义了一个 mixin,但其想法是将所有 mixin 添加到一个脚本中以便于导入。

import * as _ from 'lodash';
import xdiff from './xdiff';

interface LoDashMixins extends _.LoDashStatic {
  xdiff<T>(array:T[], values:T[]): T[];
}

_.mixin({xdiff: xdiff});

export default _ as LoDashMixins;

当您想使用 mixins 时,请导入

'./lodash-mixins'
而不是
'lodash'
。现在,您可以在编译时查看所有内置函数以及 mixin。

import _ from './lodash-mixins';

_.map([]); // built-in function still compiles
_.xdiff([], []); // mixin function compiles too

6
投票

你可以做到这一点。

// somewhere in your project
declare module _ {
    interface LoDashStatic {
        foo(value: string): number;
    }
}

// extend it somewhere else 
declare module _ {
    interface LoDashStatic {
        bar(value: number);
    }
}

测试一下


1
投票

您可以使用类型擦除来做到这一点:

import _ = require('lodash');

_.mixin(require('lodash-deep'));

function deepSet(lodash: any, path: Array<string>, record: IFooRecord, 
        replacement: number): void { 
    lodash.deepSet(object, path, replacement); 
}

interface IBarRecord {
   bar: number;
}

interface IFooRecord {
   foo: IBarRecord;
}

var subject: IFooRecord = { 
   foo: {
      bar: 0
   }
};
var replacement: number = 1;

deepSet(_, ['foo', 'bar'], subject, replacement);

这有点麻烦,但你的代码会编译。您还可以创建自己的代理来实现 mixin 的接口,并将 lodash 模块实例注入其中以实现更加模块化的结果:

import _ = require('lodash');

_.mixin(require('lodash-deep'));    

module 'lodash-deep' {

   export class lodashDeep {

     private _: any;

      constructor(lodash?: any) {
         if (!lodash) {
            lodash = _;
         }
         this._ = lodash;
      }

      public deepSet(collection: any, path: any, value: any): void {
         this._.deepSet(collection, path, value);
      }

      ...

   }

}

1
投票

目前看来,我想要的东西似乎无法毫无痛苦地获得。相反,我必须修改 lodash.d.ts 文件以包含我想要的定义,类似于以下内容:

declare module _ {
    // Default methods declared here...

    //*************************************************************************
    // START OF MIXINS, THESE ARE NOT PART OF LODASH ITSELF BUT CREATED BY US!
    //*************************************************************************

    interface LoDashStatic {
        isNonEmptyString: (str: string) => boolean;
        isEmptyString: (str: string) => boolean;
        isEmptyArray: (a: any[]) => boolean;
        isNonEmptyArray: (a: any[]) => boolean;
        isNullOrEmptyString: (str: string) => boolean;
        isNullOrUndefined: (val: any) => boolean;
        isNullOrEmpty(value: any[]): boolean;
        isNullOrEmpty(value: _.Dictionary<any>): boolean;
        isNullOrEmpty(value: string): boolean;
        isNullOrEmpty(value: any): boolean;
    }

    //*************************************************************************
    // END OF MIXINS
    //*************************************************************************

    // Default types declared here...
}

我讨厌修改默认文件,但这似乎是危害较小的一个。


1
投票

我发现关于模块增强的文档很有帮助。我结合使用了这个和另一个答案。

// my-lodash.ts
import * as _ from 'lodash';

declare module 'lodash' {
  interface LoDashStatic {
    isNonEmptyString(str: string): boolean;
    isEmptyString(str: string): boolean;
    isEmptyArray<T>(a: T[]): boolean;
    isNonEmptyArray<T>(a: T[]): boolean;
    isNullOrEmptyString(str: string): boolean;
    isNullOrUndefined<T>(val: T): boolean;
    isNullOrEmpty<T>(value: T[]): boolean;
    isNullOrEmpty<T>(value: Dictionary<T>): boolean;
    isNullOrEmpty<T>(value: T): boolean;
  }
}

module LoDash {
  export function isEmptyArray<T>(a: T): boolean {
    return Array.isArray(a) && !a.length;
  }
  // the rest of your functions
}

_.mixin(Object.keys(LoDash)
               .reduce(
                 (object, key) => {
                   object[key] = LoDash[key];
                   return object;
                 },
                 Object.create(null)
              )); 

export = _;

这样做,您可以避免强制转换或使用默认导出,这意味着您可以继续以相同的方式导入。

现在,在其他文件中,使用您的增强模块:

// another-file.ts
import * as _ from './my-lodash';

_.isEmptyArray([]);
=> true

0
投票

除了 @smartboyanswer 之外,您实际上不需要声明彼此分开的类型和实际函数。这就是您创建 mixin 并直接从中推断类型的方法:

// util/lodash.mixins.ts

import _ from 'lodash';

class LoDashMixins {
  isStringEmpty(str: string) {
    str.length === 0;
  }
  sum(a: number, b: number) {
    return a * b;
  }
  yourFunction() {
    return 'foo' as const;
  }
}

/* -------------------------- */

// This one binds your mixin functions
_.mixin(
  Object.getOwnPropertyNames(Mixins.prototype).reduce((obj, name) => {
    obj[name] = Mixins.prototype[name];
    return obj;
  }, {}),
);

// And this one mixes in your types!
declare module 'lodash' {
  interface LoDashStatic extends LoDashMixins {}
}

如上所示,您只需声明一次函数。在这种情况下,类是覆盖运行时实体和打字稿类型的好方法

© www.soinside.com 2019 - 2024. All rights reserved.