Skip to content

Commit 4fda6b3

Browse files
committed
fix(MergeDeep): optional keys VS undefined values working and tested #1208
1 parent 4a7934b commit 4fda6b3

File tree

2 files changed

+20
-23
lines changed

2 files changed

+20
-23
lines changed

source/merge-deep.d.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,9 @@ type MergeDeepRecordProperty<
3535
Default = Source, // Used for debug only
3636
>
3737
= undefined extends Source
38-
? undefined extends Destination
39-
? MergeDeepOrReturn<Default, Exclude<Destination, undefined>, Exclude<Source, undefined>, Options> | undefined
40-
: MergeDeepOrReturn<Default, Exclude<Destination, undefined>, Exclude<Source, undefined>, Options>
41-
: undefined extends Destination
42-
? MergeDeepOrReturn<Default, Exclude<Destination, undefined>, Exclude<Source, undefined>, Options> // TODO | undefined ?
43-
: MergeDeepOrReturn<Default, Destination, Source, Options>
38+
? MergeDeepOrReturn<Default, Exclude<Destination, undefined>, Exclude<Source, undefined>, Options> | undefined
39+
: MergeDeepOrReturn<Default, Exclude<Destination, undefined>, Exclude<Source, undefined>, Options>
40+
// We cannot add | undefined here to follow the behavior of merging into "unknown"
4441
;
4542

4643
/**

test-d/merge-deep.ts

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,15 @@ type OptionalNestedTest = {
194194
nested?: {
195195
in_left: string;
196196
sub_nested?: {
197-
number?: number;
197+
in_both?: number;
198198
};
199199
};
200200
};
201201
Right: {
202202
nested: {
203203
in_right: string;
204204
sub_nested: {
205-
number: number;
205+
in_both: number;
206206
};
207207
};
208208
};
@@ -217,7 +217,7 @@ expectTypeOf<OptionalNestedRightIntoLeft>().toEqualTypeOf<{
217217
in_left: string; // Subentries are kept in both directions
218218
in_right: string;
219219
sub_nested: { // Optional is ovewritten by Right in subentries
220-
number: number;
220+
in_both: number;
221221
};
222222
};
223223
}>();
@@ -231,21 +231,24 @@ expectTypeOf<OptionalNestedLeftIntoRight>().toEqualTypeOf<{
231231
in_left: string; // Subentries are kept in both directions
232232
in_right: string;
233233
sub_nested?: { // Optional is added by Left in subentries
234-
number?: number;
235-
};
236-
};
234+
in_both?: number | undefined;
235+
} | undefined;
236+
} | undefined;
237+
// "| undefined" is added here and the only way to remove it
238+
// would depend on exactOptionalPropertyTypes and a complex
239+
// logic which may not worth the effort
237240
}>();
238241

239242
// Nested Optional: Optional versus undefined entry
240243
type OptionalOrUndefinedNestedTest = {
241244
Left: {
242245
nested?: {
243-
string: string;
246+
in_left: string;
244247
};
245248
};
246249
Right: {
247250
nested: {
248-
number: number;
251+
in_right: number;
249252
} | undefined;
250253
};
251254
};
@@ -256,8 +259,8 @@ type OptionalOrUndefinedNestedRightIntoLeft = MergeDeep<
256259
>;
257260
expectTypeOf<OptionalOrUndefinedNestedRightIntoLeft>().toEqualTypeOf<{
258261
nested: { // ? is ovewritten by Right
259-
string: string;
260-
number: number;
262+
in_left: string;
263+
in_right: number;
261264
} | undefined; // Undefined is kept in both directions
262265
}>();
263266

@@ -267,8 +270,8 @@ type OptionalOrUndefinedNestedRightIntoRight = MergeDeep<
267270
>;
268271
expectTypeOf<OptionalOrUndefinedNestedRightIntoRight>().toEqualTypeOf<{
269272
nested?: { // ? is added by Left
270-
string: string;
271-
number: number;
273+
in_left: string;
274+
in_right: number;
272275
} | undefined; // Undefined is kept in both directions
273276
}>();
274277

@@ -294,9 +297,7 @@ expectTypeOf<OptionalAndUndefinedNestedRightIntoLeft>().toEqualTypeOf<{
294297
nested: {
295298
in_left: string;
296299
in_right: string;
297-
}; // Undefined is overwritten by Right
298-
// | undefined;
299-
// TODO Should we preserve the "| undefined" there?
300+
}; // "| undefined" is removed by Right
300301
}>();
301302

302303
type OptionalAndUndefinedNestedRightIntoRight = MergeDeep<
@@ -307,8 +308,7 @@ expectTypeOf<OptionalAndUndefinedNestedRightIntoRight>().toEqualTypeOf<{
307308
nested?: {
308309
in_left: string;
309310
in_right: string;
310-
}; // Undefined is not kept as redundant
311-
// TODO is there a way to force the undefined to be there? Should we?
311+
} | undefined; // "| undefined" is added by Left
312312
}>();
313313

314314
// Test for readonly

0 commit comments

Comments
 (0)