TypeScript 4.0 beta describes tuple operations without enumerating lengths
Generic tuple spreads let one signature preserve the order and types of concatenated inputs. Labeled elements improve how those argument lists appear to callers.
Concatenating two arrays is a small JavaScript operation, but describing it precisely for tuples has required many TypeScript overloads. Each overload covers another combination of input lengths and element types. The TypeScript 4.0 beta announced June 26 adds generic tuple spreads so one signature can express the relationship directly.
The problem is not accepting an arbitrary array. A broad array signature can already do that. The problem is preserving that a particular element occupies a particular position in the result. A tuple operation should not have to discard ordering information merely because its inputs have lengths the library author did not enumerate.
I appreciate this kind of improvement in TypeScript because frameworks often wrap functions and forward arguments. A declaration that describes the transformation directly is easier to assess than a growing collection of nearly identical overloads. It also reduces the chance that the runtime operation supports a case the declarations forgot.
Generic spreads retain the input relationship
The beta introduces spreads whose element sequence comes from a type parameter. That lets a tuple type represent an unknown sequence now and substitute a concrete sequence when the generic is instantiated. Anders Hejlsberg's variadic tuple implementation adds compiler handling for these variable tuple elements.
The announcement also clarifies the major version number. The team describes 4.0 as a continuation of its existing upgrade policy, with no substantially larger collection of breaking changes simply because the leading version digit changes.
The announcement combines two such sequences in a concatenation function. A version using unknown for the broad element constraint keeps the input collections readonly while returning a new tuple.
type Items = readonly unknown[];
function concat<T extends Items, U extends Items>(
left: T,
right: U
): [...T, ...U] {
return [...left, ...right];
}
const result = concat(["worker", 2] as const, [true] as const);
const expected: ["worker", 2, true] = result;
The return type records the first input's elements followed by the second input's elements. The as const inputs give inference specific tuples to preserve. A broad mutable array input supplies less information, so the generic signature cannot invent a fixed length that the input type does not contain.
This is a relationship between types around an existing JavaScript operation. The runtime still constructs an array through spread syntax. The new type operation models that construction without requiring a separate overload for every supported arity.
A spread no longer has to end the tuple
Earlier tuple rest syntax required the rest element to be last. The beta permits spreads at other positions, so fixed tuple sequences can be combined and flattened. Two known pairs can produce a known four-element tuple with each position preserved.
An unbounded array changes that result. The announcement explains that when a spread has no known length, consecutive elements can become part of the resulting rest element. The checker cannot preserve the same fixed-position account after an arbitrarily long sequence.
That limit is useful to understand before treating variadic tuples as a general guarantee of exact argument positions. Exact information depends on what the input type supplies. A tuple of known length and an array of unknown length express different constraints, even when a particular runtime array happens to contain only two items.
The beta's tail example demonstrates the same principle in reverse. A leading element can be removed while the remaining generic sequence survives in the return type. The author describes the transformation once, and inference supplies the concrete remaining positions for a tuple input.
Function argument lists gain a compositional description
The announcement also shows partial application. A helper accepts a function and an initial sequence of arguments, then returns a function requiring the remaining sequence. Generic tuple spreads describe the full parameter list as the combination of those two parts.
This is more precise than returning a function with an unconstrained rest array. The remaining argument types and count can still be checked. Passing the wrong initial argument or too many initial arguments also conflicts with the original function's parameter list.
I want wrappers to preserve the contract of the function they wrap. Variadic tuples make that possible for more argument-list operations without demanding a hand-written signature for each call shape. The feature still depends on the helper's implementation matching its declared transformation.
Labels document positions without changing compatibility
The beta adds labeled tuple elements alongside variadic tuples. A type such as [start: number, end: number] communicates the role of two numeric positions. Those labels improve documentation and tooling, but do not change the values accepted by the tuple type.
Labels also do not force destructuring variables to use the same names. A caller can choose local names while the declaration preserves its explanation of each position. In this beta, labeling one element requires labeling the other elements in that tuple as well.
Together these features address different weaknesses in tuple-based APIs. Generic spreads express how argument sequences change. Labels explain the positions that remain visible to a caller. A helper can preserve a function's parameter relationship while exposing an argument list that the editor can describe meaningfully.