- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.1k
Description
🔎 Search Terms
"distribution union"
I have a type DistributeOverTupleElementTypes that is intended to operate on a tuple type and to distribute over the component union elements. Example:
DistributeOverTupleElementTypes<[number | boolean, string | 5]> is expected to evaluate to  [number, string] | [number, 5] | [boolean, string] | [boolean, 5] and it works as expected (see t1 below). However, when replacing type "5" with type "[5]", the expected evaluation result misses the components [boolean, string] and [boolean, [5]] (see t2, t3, t4 and t5). Why? Is the behavioral difference intended?
type DistributeOverTupleElementTypes<T> =
    T extends [infer SingleComponent]
       ? (SingleComponent extends unknown // enforce distribution
          ? [SingleComponent]
          : never)
       : (T extends [infer First, ...infer Rest]
          ? (First extends unknown // enforce distribution
             ? (DistributeOverTupleElementTypes<Rest> extends infer EvaluatedRestU
                ? (EvaluatedRestU extends infer FixedEvaluatedRestTuple // enforce distribution
                   ? (FixedEvaluatedRestTuple extends unknown[]
                      ? [First, ...FixedEvaluatedRestTuple]
                      : never)
                   : never)
                : never)
             : never)
          : never);
const t1: [number, string] | [number, 5] | [boolean, string] | [boolean, 5] extends  DistributeOverTupleElementTypes<[number | boolean, string | 5]> ? true : false = true;
const t2: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> ? true : false = true;  //!! error
const t3: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, string] ? true : false = true; // !!error
const t4: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, [5]] ? true : false = true; // !!error
const t5: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, string] | [boolean, [5]] ? true : false = true;
// Thus, the evaluation result of DistributeOverTupleElementTypes<[number | boolean, string | [5]]> misses the union components [boolean, string] and [boolean, [5]]. Why?
const t6: [number, string | [5]] | [boolean, string | [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | 5]> ? true : false = true; // !!errorOutput
"use strict";
const t1 = true;
const t2 = true; //!! error
const t3 = true; // !!error
const t4 = true; // !!error
const t5 = true;
// Thus, the evaluation result of DistributeOverTupleElementTypes<[number | boolean, string | [5]]> misses the union components [boolean, string] and [boolean, [5]]. Why?
const t6 = true; // !!errorCompiler Options
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictPropertyInitialization": true,
    "strictBindCallApply": true,
    "noImplicitThis": true,
    "noImplicitReturns": true,
    "alwaysStrict": true,
    "esModuleInterop": true,
    "declaration": true,
    "target": "ES2017",
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "node"
  }
}Playground Link: Provided
🕗 Version & Regression Information
- This is the behavior in every version I tried starting with version 5.04 up to 5.8.3 and the Nightly version as of 2025-05-22.
⏯ Playground Link
💻 Code
type DistributeOverTupleElementTypes<T> =
    T extends [infer SingleComponent]
       ? (SingleComponent extends unknown // enforce distribution
          ? [SingleComponent]
          : never)
       : (T extends [infer First, ...infer Rest]
          ? (First extends unknown // enforce distribution
             ? (DistributeOverTupleElementTypes<Rest> extends infer EvaluatedRestU
                ? (EvaluatedRestU extends infer FixedEvaluatedRestTuple // enforce distribution
                   ? (FixedEvaluatedRestTuple extends unknown[]
                      ? [First, ...FixedEvaluatedRestTuple]
                      : never)
                   : never)
                : never)
             : never)
          : never);
const t1: [number, string] | [number, 5] | [boolean, string] | [boolean, 5] extends  DistributeOverTupleElementTypes<[number | boolean, string | 5]> ? true : false = true;
const t2: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> ? true : false = true;  //!! error
const t3: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, string] ? true : false = true; // !!error
const t4: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, [5]] ? true : false = true; // !!error
const t5: [number, string] | [number, [5]] | [boolean, string] | [boolean, [5]] extends  DistributeOverTupleElementTypes<[number | boolean, string | [5]]> | [boolean, string] | [boolean, [5]] ? true : false = true;
// Thus, the evaluation result of DistributeOverTupleElementTypes<[number | boolean, string | [5]]> misses the union components [boolean, string] and [boolean, [5]]. Why?🙁 Actual behavior
Assignments to variables t2, t3 and t4 are flagged as faulty (Type 'true' is not assignable to type 'false'.(2322)).
🙂 Expected behavior
Assignments to variables t2, t3 and t4 are OK because the respectively declared types should evaluate to "true".
Additional information about the issue
No response