Skip to content

Commit f23c4e4

Browse files
authored
Merge pull request #32 from kakasoo/kakasoo/fix-deep-pick-union
fix: handle Date as leaf type in DeepStrictMerge
2 parents c5720b0 + 1429669 commit f23c4e4

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

src/types/DeepStrictMerge.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,33 @@ namespace DeepStrictMerge {
1515
[key in keyof Target | keyof Source]: key extends keyof Target
1616
? key extends keyof Source
1717
? Target[key] extends object
18-
? Source[key] extends object
19-
? Target[key] extends Array<infer TE extends object>
20-
? Source[key] extends Array<infer PE extends object>
21-
? Array<Infer<TE, PE>> // If both are arrays of objects, merge their elements into a new array
22-
: never // If one is an array and the other is not, merging is not possible
23-
: Infer<Target[key], Source[key]> // If both are objects, merge them recursively
24-
: Target[key] // If `Target` is an object but `Source` is not, take `Target`'s value
18+
? Target[key] extends Date
19+
? Target[key] // Date is a leaf type, Target wins
20+
: Source[key] extends object
21+
? Source[key] extends Date
22+
? Target[key] // Source is Date leaf, Target (non-Date object) wins
23+
: Target[key] extends Array<infer TE extends object>
24+
? Source[key] extends Array<infer PE extends object>
25+
? Array<Infer<TE, PE>> // If both are arrays of objects, merge their elements into a new array
26+
: never // If one is an array and the other is not, merging is not possible
27+
: Infer<Target[key], Source[key]> // If both are objects, merge them recursively
28+
: Target[key] // If `Target` is an object but `Source` is not, take `Target`'s value
2529
: Target[key] // If `Target` is not an object, take `Target`'s value
2630
: Target[key] // If `key` is only in `Target`, take `Target`'s value
2731
: key extends keyof Source
2832
? key extends keyof Target
2933
? Source[key] extends object
30-
? Target[key] extends object
31-
? Target[key] extends Array<infer TE extends object>
32-
? Source[key] extends Array<infer PE extends object>
33-
? Array<Infer<TE, PE>> // If both are arrays of objects, merge their elements into a new array
34-
: never // If one is an array and the other is not, merging is not possible
35-
: Infer<Target[key], Source[key]> // If both are objects, merge them recursively
36-
: Source[key] // If `Source` is an object but `Target` is not, take `Source`'s value
34+
? Source[key] extends Date
35+
? Target[key] // Date is a leaf type, Target wins
36+
: Target[key] extends object
37+
? Target[key] extends Date
38+
? Target[key] // Target is Date leaf, preserve as-is
39+
: Target[key] extends Array<infer TE extends object>
40+
? Source[key] extends Array<infer PE extends object>
41+
? Array<Infer<TE, PE>> // If both are arrays of objects, merge their elements into a new array
42+
: never // If one is an array and the other is not, merging is not possible
43+
: Infer<Target[key], Source[key]> // If both are objects, merge them recursively
44+
: Source[key] // If `Source` is an object but `Target` is not, take `Source`'s value
3745
: Source[key] // If `Source` is not an object, take `Source`'s value
3846
: Source[key] // If `key` is only in `Source`, take `Source`'s value
3947
: never; // If `key` is in neither `Target` nor `Source`, return `never`

test/features/DeepStrictMerge.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,30 @@ export function test_types_deep_strict_merge_source_only_nested() {
9191
type Answer = Equal<Question, { a: { b: number; c: string }; d: boolean }>;
9292
ok(typia.random<Answer>());
9393
}
94+
95+
/**
96+
* Tests that DeepStrictMerge preserves Date properties from both Target and Source.
97+
*/
98+
export function test_types_deep_strict_merge_date_preserved() {
99+
type Question = DeepStrictMerge<{ createdAt: Date }, { updatedAt: Date }>;
100+
type Answer = Equal<Question, { createdAt: Date; updatedAt: Date }>;
101+
ok(typia.random<Answer>());
102+
}
103+
104+
/**
105+
* Tests that DeepStrictMerge preserves Date when both Target and Source have the same Date key.
106+
*/
107+
export function test_types_deep_strict_merge_overlapping_date() {
108+
type Question = DeepStrictMerge<{ date: Date }, { date: Date }>;
109+
type Answer = Equal<Question, { date: Date }>;
110+
ok(typia.random<Answer>());
111+
}
112+
113+
/**
114+
* Tests that DeepStrictMerge preserves Date in nested objects.
115+
*/
116+
export function test_types_deep_strict_merge_nested_date() {
117+
type Question = DeepStrictMerge<{ a: { createdAt: Date; b: number } }, { a: { updatedAt: Date; c: string } }>;
118+
type Answer = Equal<Question, { a: { createdAt: Date; b: number; updatedAt: Date; c: string } }>;
119+
ok(typia.random<Answer>());
120+
}

0 commit comments

Comments
 (0)