Use intersection types to correctly infer the result of _.merge in lodash

This commit is contained in:
Tim Perry
2015-12-01 22:37:18 +01:00
parent fb2b3b1e06
commit 4e4ffc7ecf
2 changed files with 98 additions and 50 deletions

View File

@@ -6540,48 +6540,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 };
result = _.merge<{}, {}, TResult>({}, {});
result = _.merge<{}, {}, TResult>({}, {}, customizer);
result = _.merge<{}, {}, TResult>({}, {}, customizer, any);
var initialValue = { a : 1 };
var mergingValue = { b : "hi" };
result = _.merge<{}, {}, {}, TResult>({}, {}, {});
result = _.merge<{}, {}, {}, TResult>({}, {}, {}, customizer);
result = _.merge<{}, {}, {}, TResult>({}, {}, {}, customizer, any);
type ExpectedResult = { a: number, b: string };
let result: ExpectedResult;
result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {});
result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer);
result = _.merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer, any);
let customizer: (value: any, srcValue: any, key?: string, object?: InitialValue, source?: MergingValue) => any;
result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {});
result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {}, customizer);
result = _.merge<{}, {}, {}, {}, {}, TResult>({}, {}, {}, {}, {}, customizer, any);
// Test for basic merging
result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {});
result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {}, customizer);
result = _.merge<{}, TResult>({}, {}, {}, {}, {}, {}, customizer, any);
result = _.merge(initialValue, mergingValue);
result = _.merge(initialValue, mergingValue, customizer);
result = _.merge(initialValue, mergingValue, customizer, any);
result = _({}).merge<{}, TResult>({}).value();
result = _({}).merge<{}, TResult>({}, customizer).value();
result = _({}).merge<{}, TResult>({}, customizer, any).value();
result = _.merge(initialValue, {}, mergingValue);
result = _.merge(initialValue, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, mergingValue, customizer, any);
result = _({}).merge<{}, {}, TResult>({}, {}).value();
result = _({}).merge<{}, {}, TResult>({}, {}, customizer).value();
result = _({}).merge<{}, {}, TResult>({}, {}, customizer, any).value();
result = _.merge(initialValue, {}, {}, mergingValue);
result = _.merge(initialValue, {}, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, {}, mergingValue, customizer, any);
result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}).value();
result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}, customizer).value();
result = _({}).merge<{}, {}, {}, TResult>({}, {}, {}, customizer, any).value();
result = _.merge(initialValue, {}, {}, {}, mergingValue);
result = _.merge(initialValue, {}, {}, {}, mergingValue, customizer);
result = _.merge(initialValue, {}, {}, {}, mergingValue, customizer, any);
result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}).value();
result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer).value();
result = _({}).merge<{}, {}, {}, {}, TResult>({}, {}, {}, {}, customizer, any).value();
// 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 = _(initialValue).merge(mergingValue).value();
result = _(initialValue).merge(mergingValue, customizer).value();
result = _(initialValue).merge(mergingValue, customizer, any).value();
result = _(initialValue).merge({}, mergingValue).value();
result = _(initialValue).merge({}, mergingValue, customizer).value();
result = _(initialValue).merge({}, mergingValue, customizer, any).value();
result = _(initialValue).merge({}, {}, mergingValue).value();
result = _(initialValue).merge({}, {}, mergingValue, customizer).value();
result = _(initialValue).merge({}, {}, mergingValue, customizer, any).value();
result = _(initialValue).merge({}, {}, {}, mergingValue).value();
result = _(initialValue).merge({}, {}, {}, mergingValue, customizer).value();
result = _(initialValue).merge({}, {}, {}, mergingValue, customizer, any).value();
// 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();
// Test complex multiple combinations with chaining
var complicatedResult: ComplicatedExpectedType = _({ a: 1 }).merge({ b: "string" },
{ c: {} },
{ d: [1] },
{ e: true }).value();
// Test for type overriding with chaining
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

36
lodash/lodash.d.ts vendored
View File

@@ -11107,40 +11107,40 @@ 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,
@@ -11148,13 +11148,13 @@ declare module _ {
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;
}
@@ -11163,44 +11163,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