Type a spread that prepends to a tuple and one that merges two objects
Write two helpers.
prepend takes a value and a tuple and returns a new tuple with that value in front. The result must be typed [H, ...T] — each original position keeps its own type — not (H | T[number])[].
merge takes two objects and returns their spread. A key present in both must end up with the second object's type, exactly as the runtime spread behaves.
Constraints: no any, no Function, no type assertion.
export function prepend<H, T extends unknown[]>(head: H, tail: T) {
// your code here
}
export function merge<A extends object, B extends object>(a: A, b: B) {
// your code here
}
Write the implementation.
A rest element preserves positions: prepend typed [H, ...T] keeps every index, while a plain array gives only T[]. Object spread overwrites, as at run time: a key present in both takes the second object's type. No any, no assertion.
- ✗Annotating the prepend result as an array of the union, throwing away every position
- ✗Expecting an overlapping key to take its type from the first object rather than the second
- ✗Reaching for a type assertion to recover the tuple instead of a rest element in the return type
- →What does spreading a plain array rather than a tuple lose?
- →Why does a spread of two generic parameters produce
A & Brather than an overwritten shape?
A tuple keeps its positions only through a rest element in the return type; inference on its own widens the array literal to (H | T[number])[].
export function prepend<H, T extends unknown[]>(head: H, tail: T): [H, ...T] {
return [head, ...tail];
}
export function merge<A extends object, B extends object>(a: A, b: B) {
return { ...a, ...b }; // inferred as A & B
}
const t = prepend('id', [1, true] as const); // [string, 1, true]
const m = merge({ n: 1 }, { n: 'x' }); // n comes from the second object
it was, with its own type. A plain array carries no such information — spreading a T[] just gives you another T[].
overlapping key the second object wins, exactly as at run time. For generic A/B it cannot know the keys ahead of time and produces A & B. Annotating A | B would be wrong — the result carries the keys of both, not of one or the other.
- The tuple.
[H, ...T]is a tuple with a rest element: every position ofTstays where - The objects. For concrete types the compiler computes the overwritten shape: on an