Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions src/types/DeepStrictMerge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,7 @@ namespace DeepStrictMerge {
: Target[key] // If `Target` is not an object, take `Target`'s value
: Target[key] // If `key` is only in `Target`, take `Target`'s value
: key extends keyof Source
? key extends keyof Target
? Source[key] extends object
? Source[key] extends Date
? Target[key] // Date is a leaf type, Target wins
: Target[key] extends object
? Target[key] extends Date
? Target[key] // Target is Date leaf, preserve as-is
: Target[key] extends Array<infer TE extends object>
? Source[key] extends Array<infer PE extends object>
? Array<Infer<TE, PE>> // If both are arrays of objects, merge their elements into a new array
: never // If one is an array and the other is not, merging is not possible
: Infer<Target[key], Source[key]> // If both are objects, merge them recursively
: Source[key] // If `Source` is an object but `Target` is not, take `Source`'s value
: Source[key] // If `Source` is not an object, take `Source`'s value
: Source[key] // If `key` is only in `Source`, take `Source`'s value
? Source[key] // If `key` is only in `Source`, take `Source`'s value
: never; // If `key` is in neither `Target` nor `Source`, return `never`
};
}
Expand Down
41 changes: 41 additions & 0 deletions test/features/DeepStrictMerge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,3 +118,44 @@ export function test_types_deep_strict_merge_nested_date() {
type Answer = Equal<Question, { a: { createdAt: Date; b: number; updatedAt: Date; c: string } }>;
ok(typia.random<Answer>());
}

/**
* Tests that a Source-only key with a Date value is taken directly from Source.
* This proves the dead-code branch (re-checking `key extends keyof Target`) was unreachable:
* if `key` is only in Source, the result must be `Source[key]` regardless of type.
*/
export function test_types_deep_strict_merge_source_only_date() {
type Question = DeepStrictMerge<{ a: number }, { createdAt: Date }>;
type Answer = Equal<Question, { a: number; createdAt: Date }>;
ok(typia.random<Answer>());
}

/**
* Tests that a Source-only key with a nested object value is taken directly from Source.
* The dead code attempted to recursively merge Source[key] with Target[key],
* but Target[key] doesn't exist for Source-only keys.
*/
export function test_types_deep_strict_merge_source_only_nested_object() {
type Question = DeepStrictMerge<{ a: number }, { b: { c: string; d: boolean } }>;
type Answer = Equal<Question, { a: number; b: { c: string; d: boolean } }>;
ok(typia.random<Answer>());
}

/**
* Tests that a Source-only key with an array-of-objects value is taken directly from Source.
* The dead code attempted to merge array elements, but that's impossible for Source-only keys.
*/
export function test_types_deep_strict_merge_source_only_array_of_objects() {
type Question = DeepStrictMerge<{ a: number }, { items: { id: number; name: string }[] }>;
type Answer = Equal<Question, { a: number; items: { id: number; name: string }[] }>;
ok(typia.random<Answer>());
}

/**
* Tests that a Source-only key with a deeply nested object is taken as-is from Source.
*/
export function test_types_deep_strict_merge_source_only_deeply_nested_object() {
type Question = DeepStrictMerge<{ x: number }, { y: { z: { w: string; v: Date } } }>;
type Answer = Equal<Question, { x: number; y: { z: { w: string; v: Date } } }>;
ok(typia.random<Answer>());
}