Annotated solution
Published August 26, 2026The solution
type Merge<A, B> = { [K in keyof A | keyof B]: K extends keyof B ? B[K] : K extends keyof A ? A[K] : never }
The common wrong answer
type Merge<A, B> = A & BAn intersection is not a merge. For disjoint keys it is merely the wrong *shape* — assignable to the answer but not equal to it. For a shared key it is actively wrong: `{ a: string } & { a: number }` demands a value that is both, so the property becomes `never` instead of letting `B` override `A`.
Line by line
K in keyof A | keyof BMapping over the union of both key sets is what produces a single flat object. Because the key set is computed rather than a bare `keyof T`, this mapping is not homomorphic — modifiers from either source are dropped.
K extends keyof B ? B[K]Precedence is expressed by order. Testing `B` first means a shared key resolves to `B`’s type and `A` is never consulted; swapping the two branches would give you an `A`-wins merge for free.
Takeaway
Intersection composes constraints; merging replaces them. They coincide only when the key sets are disjoint, which is why `A & B` seems to work right up until two objects share a field.
