ts-pattern icon indicating copy to clipboard operation
ts-pattern copied to clipboard

Exhaustiveness check fails when matching arrays with 2 or more elements

Open allan-cannon opened this issue 8 months ago • 0 comments

Describe the bug

This code fails the exhaustiveness check even though all cases have been covered. In this case my intent is to use up to the first 2 strings in an array of unknown length with different handling depending on the number of strings.

const stringList: string[] = [];

match(stringList)
  .with([], () => {})
  .with([P.string], () => {})
  .with([P.string, P.string], () => {})
  .with([P.string, P.string, ...P.array(P.string)], () => {})
  .exhaustive(); // Type 'NonExhaustiveError<[string, ...string[]]>' has no call signatures.

The actual matching appears to be working as expected, just the exhaustiveness check is wrong. For example this code resolves the exhaustiveness check but the last with branch is unreachable.

const stringList: string[] = [];

match(stringList)
  .with([], () => {})
  .with([P.string], () => {})
  .with([P.string, P.string], () => {})
  .with([P.string, P.string, ...P.array(P.string)], () => {})
  .with([P.string, ...P.array(P.string)], () => {}) // This branch is unreachable
  .exhaustive(); // No exhaustiveness error

This code "works" but the type of the second item is string | undefined which is not what I'm looking for.

const stringList: string[] = [];

match(stringList)
  .with([], () => {})
  .with([P.string], () => {})
  .with([P.string, ...P.array(P.string)], ([first, second]) => {}) // second is type string | undefined
  .exhaustive(); // no exhaustiveness error

TypeScript playground with a minimal reproduction case

Playground

Versions

  • TypeScript version: 5.8.3
  • ts-pattern version: 5.7.0
  • environment: chrome

allan-cannon avatar May 14 '25 16:05 allan-cannon