Files
scriptc/tests/corpus/8527-array-callbacks-undefined-elements.ts
T
Malte UblandClaude Opus 5.5 223973a56b Store a discarding mapper's answer as an undefined array element
`Array.from({ length: n }, () => undefined)` and `.map(() => undefined)`
type as `undefined[]`, which the type mapping represents as an array of
unit-union elements. Callback-driven producers take the element from the
lowered callback's return type, and a standalone `undefined` in return
position maps to the void convention — its answer is erased before it
could be stored — so every discarding callback was refused (SC2009; pi's
tui terminal-color palette).

A producer whose result element is the unit-only union now gives the
callback that union as its contextual return, exactly as the array
element mapping substitutes it for a `void` element: the arrow's
`undefined` answer becomes the present unit value. `[undefined, ...]`,
sparse literals and an explicit `undefined[]` annotation already had
that representation.

Corpus 8527 pins the palette field, the mapper's call order and index,
the `.map` and `Array.from(array, ...)` forms, `in`/JSON and the empty
case under Node and natively.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 05:38:09 -07:00

45 lines
1.6 KiB
TypeScript

// Array producers whose callback answers `undefined`: the result is an
// `undefined[]`, whose elements are PRESENT undefined values (JSON prints
// them as null, `in` sees them), and the mapper still runs once per index.
type PendingQuery = {
palette: undefined[];
timer: number | undefined;
};
function build(n: number): PendingQuery {
return {
palette: Array.from({ length: n }, () => undefined),
timer: undefined,
};
}
const query = build(3);
console.log(query.palette.length);
console.log(query.palette[0] === undefined, query.palette[2] === undefined);
console.log(0 in query.palette, 2 in query.palette, 3 in query.palette);
console.log(query.timer === undefined);
// The mapper runs once per index, in order.
const seen: number[] = [];
const mapped: undefined[] = Array.from({ length: 4 }, (_value, index) => {
seen.push(index);
return undefined;
});
console.log(mapped.length, seen.join(","));
console.log(mapped.every((value) => value === undefined));
// Array.from over an existing array, and `.map` over an existing array,
// both with a discarding mapper.
const fromArray: undefined[] = Array.from([1, 2, 3], (_n) => undefined);
console.log(fromArray.length, fromArray[0] === undefined);
const discarded: undefined[] = ["a", "b"].map((_text) => undefined);
console.log(discarded.length, discarded[1] === undefined);
// A dense literal of undefined elements keeps the same shape.
const literal: undefined[] = [undefined, undefined];
console.log(literal.length, literal[1] === undefined);
console.log(JSON.stringify(query.palette));
console.log(JSON.stringify(mapped));