Skip to content

Fix StaticUnion regression for non-tuple Array<TSchema>#1598

Open
jackyzha0 wants to merge 1 commit into
sinclairzx81:mainfrom
jackyzha0:fix/static-union-non-tuple-array
Open

Fix StaticUnion regression for non-tuple Array<TSchema>#1598
jackyzha0 wants to merge 1 commit into
sinclairzx81:mainfrom
jackyzha0:fix/static-union-non-tuple-array

Conversation

@jackyzha0
Copy link
Copy Markdown

@jackyzha0 jackyzha0 commented May 15, 2026

In typebox 0.34, UnionStatic used a mapped-index-signature pattern {[K in keyof T]: Static<T[K]>}[number] that resolved correctly for both tuple types and general TSchema[] arrays.

In 1.x, StaticUnion was rewritten using head/tail destructuring with a Result = never default. Because TSchema[] does not match [Left, ...Right] (the array may be empty), Static<TUnion<TSchema[]>> falls through to never. This regresses any code that builds a union from a variable typed as a plain array:

const errors = [Type.Object(...), Type.Object(...)];
const schema = Type.Union(errors);
type T = Static<typeof schema>; // resolves to `never` instead of the union

Fix: add an Array<infer Item extends TSchema> fallback that infers the element type when the input is not a tuple. Tuples still go through the fast recursive path; the new branch only fires for general arrays.

Adds static tests covering:

  • inline tuple inference (existing behaviour)
  • generic TSchema[] (must not resolve to never)
  • narrowed Array<TLiteral<1|2|3>> (must resolve to 1|2|3)

In typebox 0.34, UnionStatic used a mapped-index-signature pattern
`{[K in keyof T]: Static<T[K]>}[number]` that resolved correctly for
both tuple types and general `TSchema[]` arrays.

In 1.x, StaticUnion was rewritten using head/tail destructuring with a
`Result = never` default. Because `TSchema[]` does not match
`[Left, ...Right]` (the array may be empty), `Static<TUnion<TSchema[]>>`
falls through to `never`. This regresses any code that builds a union
from a variable typed as a plain array:

  const errors = [Type.Object(...), Type.Object(...)];
  const schema = Type.Union(errors);
  type T = Static<typeof schema>; // resolves to `never` instead of the union

Fix: add an `Array<infer Item extends TSchema>` fallback that infers the
element type when the input is not a tuple. Tuples still go through the
fast recursive path; the new branch only fires for general arrays.

Adds static tests covering:
  - inline tuple inference (existing behaviour)
  - generic TSchema[] (must not resolve to never)
  - narrowed Array<TLiteral<1|2|3>> (must resolve to 1|2|3)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant