mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
`["one"] | string[]` flowing into a `string[]` slot compiled to the checked extraction against the array arm alone, so a tuple value threw at runtime. Node accepts it: the value is an array, and nothing about a `string[]` position distinguishes which arm produced it. Let the union-width plan cover a mixed union that holds the destination arm beside a convertible one, and place that plan before the checked-extraction rule, so each arm converts on its tag (a tuple rebuilds, an array copies). A union whose only non-unit arm is the destination (`T[] | undefined`) still has nothing to convert and keeps its tested extraction. tests/corpus/8513-tuple-union-array.ts pins the binding, call-argument, readonly, and single-tuple shapes against Node. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
26 lines
984 B
TypeScript
26 lines
984 B
TypeScript
// A union that holds an array arm beside tuple arms, flowing into that array
|
|
// type: Node has one array either way, so both arms answer as arrays instead
|
|
// of the tuple arm trapping in the checked extraction.
|
|
type Mixed = ["one"] | string[];
|
|
function pick(flag: boolean): Mixed {
|
|
return flag ? ["one"] : ["two", "three"];
|
|
}
|
|
function take(value: string[]): string {
|
|
return `${value.length}:${value.join(",")}`;
|
|
}
|
|
for (const flag of [true, false]) {
|
|
const m = pick(flag);
|
|
const arr: string[] = m;
|
|
console.log(flag, arr.length, arr.join(","), take(m), arr[0]);
|
|
}
|
|
type Readonly = readonly ["a"] | readonly string[];
|
|
const r: Readonly = ["b", "c"];
|
|
const plain: readonly string[] = r;
|
|
console.log("readonly", plain.length, plain.join(","));
|
|
const narrow: ["one"] = ["one"];
|
|
const one: string[] = narrow;
|
|
console.log("single", one.length, one.join(","));
|
|
const optional: string[] | undefined = ["x"];
|
|
const lifted: string[] = optional!;
|
|
console.log("optional", lifted.length);
|