Skip to content

TypeScript 4.6 sometimes treats tuple union types as "never" when switch-case has a "default" clauseΒ #47857

Closed
@ide

Description

@ide

Bug Report

The error described below started with TypeScript 4.6.1-rc. A minimal repro is included.

πŸ”Ž Search Terms

  • Destructuring
  • Union types

πŸ•— Version & Regression Information

  • This changed between versions 4.5.5 and 4.6.1-rc

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

See this toy NAND evaluator. Something about the recursive union type causes TS to fail when destructuring the array. Deleting the default clause causes the error to go away. (The default clause is unnecessary if assuming TS is sound but one can see why a safety net is helpful.)

export type Expression = BooleanLogicExpression | 'true' | 'false';
export type BooleanLogicExpression = ['and', ...Expression[]] | ['not', Expression];

export function evaluate(expression: Expression): boolean {
  if (Array.isArray(expression)) {
    const [operator, ...operands] = expression;
    switch (operator) {
      case 'and': {
        return operands.every((child) => evaluate(child));
      }
      case 'not': {
        return !evaluate(operands[0]);
      }
      default: {
        throw new Error(`${operator} is not a supported operator`);
      }
    }
  } else {
    return expression === 'true';
  }
}

πŸ™ Actual behavior

The line const [operator, ...operands] = expression; produces the error: TS2488: Type 'never' must have a '[Symbol.iterator]()' method that returns an iterator.

πŸ™‚ Expected behavior

Expected there not to be an TS error.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFix AvailableA PR has been opened for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions