如何在 TypeScript 中使用 lodash.mixin
How to use lodash.mixin in TypeScript
我的团队正在评估将我们的一些文件从 JavaScript 转换为 TypeScript,并且我们在代码中广泛使用了一些自定义混合方法。通过一些基本测试,我们似乎可以使用 _.mixin 按照规范创建 mixins,但我们无法在不出现编译错误的情况下引用它们。当然,我们可以将这些引用放在定义文件中,但我通常不希望修改它。
有什么方法可以实现我们正在寻找的东西,还是我们运气不好?
您可以使用类型擦除来执行此操作:
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);
}
...
}
}
目前看来,我想要的东西似乎没有任何痛苦就无法获得。相反,我必须修改 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...
}
我讨厌修改默认文件,但这似乎是害处较小。
你可以做到这一点。
// somewhere in your project
declare module _ {
interface LoDashStatic {
foo(value: string): number;
}
}
// extend it somewhere else
declare module _ {
interface LoDashStatic {
bar(value: number);
}
}
请参阅 extending built-in types 上的 TypeScript 文档,我认为这也适用于此。 _
定义为 var _: _.LoDashStatic
,var
当前不可扩展。
我发现公开扩展的最佳方式是通过 lodash-mixins.ts
脚本定义新的 LoDashMixins
接口(扩展 LoDashStatic
),应用混合,并导出 _
转换为自定义界面。此示例定义了一个 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 <LoDashMixins>_;
当你想使用 mixins 时,导入 './lodash-mixins'
而不是 'lodash'
。您现在 compile-time 可以查看所有 built-in 函数以及您的混入。
import _ from './lodash-mixins';
_.map([]); // built-in function still compiles
_.xdiff([], []); // mixin function compiles too
我发现 module augmentation 上的文档很有帮助。我结合使用了这个和另一个答案。
// 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
我的团队正在评估将我们的一些文件从 JavaScript 转换为 TypeScript,并且我们在代码中广泛使用了一些自定义混合方法。通过一些基本测试,我们似乎可以使用 _.mixin 按照规范创建 mixins,但我们无法在不出现编译错误的情况下引用它们。当然,我们可以将这些引用放在定义文件中,但我通常不希望修改它。
有什么方法可以实现我们正在寻找的东西,还是我们运气不好?
您可以使用类型擦除来执行此操作:
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);
}
...
}
}
目前看来,我想要的东西似乎没有任何痛苦就无法获得。相反,我必须修改 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...
}
我讨厌修改默认文件,但这似乎是害处较小。
你可以做到这一点。
// somewhere in your project
declare module _ {
interface LoDashStatic {
foo(value: string): number;
}
}
// extend it somewhere else
declare module _ {
interface LoDashStatic {
bar(value: number);
}
}
请参阅 extending built-in types 上的 TypeScript 文档,我认为这也适用于此。 _
定义为 var _: _.LoDashStatic
,var
当前不可扩展。
我发现公开扩展的最佳方式是通过 lodash-mixins.ts
脚本定义新的 LoDashMixins
接口(扩展 LoDashStatic
),应用混合,并导出 _
转换为自定义界面。此示例定义了一个 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 <LoDashMixins>_;
当你想使用 mixins 时,导入 './lodash-mixins'
而不是 'lodash'
。您现在 compile-time 可以查看所有 built-in 函数以及您的混入。
import _ from './lodash-mixins';
_.map([]); // built-in function still compiles
_.xdiff([], []); // mixin function compiles too
我发现 module augmentation 上的文档很有帮助。我结合使用了这个和另一个答案。
// 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