Skip to content

Commit

Permalink
Merge pull request #7016 from pimterry/lodash-merge
Browse files Browse the repository at this point in the history
Use intersection types to correctly infer the result of _.merge in lodash
  • Loading branch information
vvakame committed Jan 11, 2016
2 parents 010d44d + 4e4ffc7 commit 8a02ac9
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 50 deletions.
112 changes: 80 additions & 32 deletions lodash/lodash-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8349,48 +8349,96 @@ module TestMapKeys {

// _.merge
module TestMerge {
let customizer: (value: any, srcValue: any, key?: string, object?: {}, source?: {}) => any;
let result: TResult;
type InitialValue = { a : number };
type MergingValue = { b : string };

var initialValue = { a : 1 };
var mergingValue = { b : "hi" };

type ExpectedResult = { a: number, b: string };
let result: ExpectedResult;

let customizer: (value: any, srcValue: any, key?: string, object?: InitialValue, source?: MergingValue) => any;

// Test for basic merging

result = _.merge(initialValue, mergingValue);
result = _.merge(initialValue, mergingValue, customizer);
result = _.merge(initialValue, mergingValue, customizer, any);

result = _.merge(initialValue, {}, mergingValue);
result = _.merge(initialValue, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, mergingValue, customizer, any);

result = _.merge(initialValue, {}, {}, mergingValue);
result = _.merge(initialValue, {}, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, {}, mergingValue, customizer, any);

result = _.merge(initialValue, {}, {}, {}, mergingValue);
result = _.merge(initialValue, {}, {}, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, {}, {}, mergingValue, customizer, any);

// Once we get to the varargs version, you have to specify the result explicitly
result = _.merge<ExpectedResult>(initialValue, {}, {}, {}, {}, mergingValue);
result = _.merge<ExpectedResult>(initialValue, {}, {}, {}, {}, mergingValue, customizer);
result = _.merge<ExpectedResult>(initialValue, {}, {}, {}, {}, mergingValue, customizer, any);

// Test for multiple combinations of many types

type ComplicatedExpectedType = { a: number, b: string, c: {}, d: number[], e: boolean };

var complicatedResult: ComplicatedExpectedType = _.merge({ a: 1 },
{ b: "string" },
{ c: {} },
{ d: [1] },
{ e: true });
// Test for type overriding

type ExpectedTypeAfterOverriding = { a: boolean };

var overriddenResult: ExpectedTypeAfterOverriding = _.merge({ a: 1 },
{ a: "string" },
{ a: {} },
{ a: [1] },
{ a: true });

// Tests for basic chaining with merge

result = _.merge<{}, {}, TResult>({}, {});
result = _.merge<{}, {}, TResult>({}, {}, customizer);
result = _.merge<{}, {}, TResult>({}, {}, customizer, any);
result = _(initialValue).merge(mergingValue).value();
result = _(initialValue).merge(mergingValue, customizer).value();
result = _(initialValue).merge(mergingValue, customizer, any).value();

result = _.merge<{}, {}, {}, TResult>({}, {}, {});
result = _.merge<{}, {}, {}, TResult>({}, {}, {}, customizer);
result = _.merge<{}, {}, {}, TResult>({}, {}, {}, customizer, any);
result = _(initialValue).merge({}, mergingValue).value();
result = _(initialValue).merge({}, mergingValue, customizer).value();
result = _(initialValue).merge({}, mergingValue, customizer, any).value();

result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {});
result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer);
result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer, any);
result = _(initialValue).merge({}, {}, mergingValue).value();
result = _(initialValue).merge({}, {}, mergingValue, customizer).value();
result = _(initialValue).merge({}, {}, mergingValue, customizer, any).value();

result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {});
result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {}, customizer);
result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {}, customizer, any);
result = _(initialValue).merge({}, {}, {}, mergingValue).value();
result = _(initialValue).merge({}, {}, {}, mergingValue, customizer).value();
result = _(initialValue).merge({}, {}, {}, mergingValue, customizer, any).value();

result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {});
result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {}, customizer);
result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {}, customizer, any);
// Once we get to the varargs version, you have to specify the result explicitly
result = _(initialValue).merge<ExpectedResult>({}, {}, {}, {}, mergingValue).value();
result = _(initialValue).merge<ExpectedResult>({}, {}, {}, {}, mergingValue, customizer).value();
result = _(initialValue).merge<ExpectedResult>({}, {}, {}, {}, mergingValue, customizer, any).value();

result = _({}).merge<{}, TResult>({}).value();
result = _({}).merge<{}, TResult>({}, customizer).value();
result = _({}).merge<{}, TResult>({}, customizer, any).value();
// Test complex multiple combinations with chaining

result = _({}).merge<{}, {}, TResult>({}, {}).value();
result = _({}).merge<{}, {}, TResult>({}, {}, customizer).value();
result = _({}).merge<{}, {}, TResult>({}, {}, customizer, any).value();
var complicatedResult: ComplicatedExpectedType = _({ a: 1 }).merge({ b: "string" },
{ c: {} },
{ d: [1] },
{ e: true }).value();

result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}).value();
result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}, customizer).value();
result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}, customizer, any).value();
// Test for type overriding with chaining

result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}).value();
result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer).value();
result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer, any).value();
var overriddenResult: ExpectedTypeAfterOverriding = _({ a: 1 }).merge({ a: "string" },
{ a: {} },
{ a: [1] },
{ a: true }).value();

result = _({}).merge<TResult>({}, {}, {}, {}, {}).value();
result = _({}).merge<TResult>({}, {}, {}, {}, {}, customizer).value();
result = _({}).merge<TResult>({}, {}, {}, {}, {}, customizer, any).value();
}

// _.methods
Expand Down
36 changes: 18 additions & 18 deletions lodash/lodash.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12948,54 +12948,54 @@ declare module _ {
* @param thisArg The this binding of customizer.
* @return Returns object.
*/
merge<TObject, TSource, TResult>(
merge<TObject, TSource>(
object: TObject,
source: TSource,
customizer?: MergeCustomizer,
thisArg?: any
): TResult;
): TObject & TSource;

/**
* @see _.merge
*/
merge<TObject, TSource1, TSource2, TResult>(
merge<TObject, TSource1, TSource2>(
object: TObject,
source1: TSource1,
source2: TSource2,
customizer?: MergeCustomizer,
thisArg?: any
): TResult;
): TObject & TSource1 & TSource2;

/**
* @see _.merge
*/
merge<TObject, TSource1, TSource2, TSource3, TResult>(
merge<TObject, TSource1, TSource2, TSource3>(
object: TObject,
source1: TSource1,
source2: TSource2,
source3: TSource3,
customizer?: MergeCustomizer,
thisArg?: any
): TResult;
): TObject & TSource1 & TSource2 & TSource3;

/**
* @see _.merge
*/
merge<TObject, TSource1, TSource2, TSource3, TSource4, TResult>(
merge<TObject, TSource1, TSource2, TSource3, TSource4>(
object: TObject,
source1: TSource1,
source2: TSource2,
source3: TSource3,
source4: TSource4,
customizer?: MergeCustomizer,
thisArg?: any
): TResult;
): TObject & TSource1 & TSource2 & TSource3 & TSource4;

/**
* @see _.merge
*/
merge<TObject, TResult>(
object: TObject,
merge<TResult>(
object: any,
...otherArgs: any[]
): TResult;
}
Expand All @@ -13004,44 +13004,44 @@ declare module _ {
/**
* @see _.merge
*/
merge<TSource, TResult>(
merge<TSource>(
source: TSource,
customizer?: MergeCustomizer,
thisArg?: any
): LoDashImplicitObjectWrapper<TResult>;
): LoDashImplicitObjectWrapper<T & TSource>;

/**
* @see _.merge
*/
merge<TSource1, TSource2, TResult>(
merge<TSource1, TSource2>(
source1: TSource1,
source2: TSource2,
customizer?: MergeCustomizer,
thisArg?: any
): LoDashImplicitObjectWrapper<TResult>;
): LoDashImplicitObjectWrapper<T & TSource1 & TSource2>;

/**
* @see _.merge
*/
merge<TSource1, TSource2, TSource3, TResult>(
merge<TSource1, TSource2, TSource3>(
source1: TSource1,
source2: TSource2,
source3: TSource3,
customizer?: MergeCustomizer,
thisArg?: any
): LoDashImplicitObjectWrapper<TResult>;
): LoDashImplicitObjectWrapper<T & TSource1 & TSource2 & TSource3>;

/**
* @see _.merge
*/
merge<TSource1, TSource2, TSource3, TSource4, TResult>(
merge<TSource1, TSource2, TSource3, TSource4>(
source1: TSource1,
source2: TSource2,
source3: TSource3,
source4: TSource4,
customizer?: MergeCustomizer,
thisArg?: any
): LoDashImplicitObjectWrapper<TResult>;
): LoDashImplicitObjectWrapper<T & TSource1 & TSource2 & TSource3 & TSource4>;

/**
* @see _.merge
Expand Down

0 comments on commit 8a02ac9

Please sign in to comment.