Skip to content

Fix Array.flatten type inference loss (#5963)#5981

Merged
tim-smart merged 4 commits intoEffect-TS:mainfrom
bxff:fix/array-flatten-inference
Jan 20, 2026
Merged

Fix Array.flatten type inference loss (#5963)#5981
tim-smart merged 4 commits intoEffect-TS:mainfrom
bxff:fix/array-flatten-inference

Conversation

@bxff
Copy link
Copy Markdown
Contributor

@bxff bxff commented Jan 14, 2026

Type

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Description

This PR resolves a type inference regression in Array.flatten where contravariant type parameters (like Effect requirements) were being prematurely unified, causing loss of precision in requirement unions.

Problem Statement

When flattening nested arrays containing types with contravariant parameters, TypeScript's inference would collapse union types in contravariant positions. For example, flattening [[Effect<R1 | R2>], [Effect<R1 | R2 | R3>]] would incorrectly lose the R3 requirement in the resulting union.

Solution Overview

The fix implements two key improvements:

  1. Distributive Indexed Access: Updated ReadonlyArray.Flatten to use T[number][number] instead of infer A. This correctly extracts and unions element types from nested arrays while preserving contravariant structure.

  2. Const Generic Modifier: Added const modifier to the S generic parameter in the flatten function, enabling optional precision preservation for literal tuple structures.

Core Changes

  • packages/effect/src/Array.ts:

    • ReadonlyArray.Flatten: Replaced infer A with distributive indexed access T[number][number]
    • flatten: Added const modifier to generic parameter S
  • package.json:

    • Restored @effect/docgen to stable version ^0.5.2 (fixes 404 from preview build)
  • Regression Tests:

    • Added Array.flatten inference tests preserving Effect requirement unions in dtslint/Array.tst.ts
    • Added pipe literal tuple handling test in dtslint/Function.tst.ts

Verification Results

Type-level testing: Full dtslint suite passes successfully:

  • 55 test files, 772 tests, 3523 assertions

Reproduction Example

interface Effect<R> { 
  readonly _R: (_: R) => void 
}

interface R1 { _r1: unique symbol }
interface R2 { _r2: unique symbol }
interface R3 { _r3: unique symbol }

declare const arg1: Effect<R1 | R2>
declare const arg2: Effect<R1 | R2 | R3>

// Result element type is now correctly Eff<R1 | R2 | R3> | Eff<R1 | R2>
// which correctly preserves the union of requirements when simplified.
const result = Array.flatten([[arg1], [arg2]])

All contributing guidelines, tests, and documentation requirements have been satisfied.

Related

@bxff bxff requested a review from mikearnaldi as a code owner January 14, 2026 07:37
@github-project-automation github-project-automation bot moved this to Discussion Ongoing in PR Backlog Jan 14, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jan 14, 2026

🦋 Changeset detected

Latest commit: fb3dc8d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 36 packages
Name Type
effect Patch
@effect/cli Patch
@effect/cluster Patch
@effect/experimental Patch
@effect/opentelemetry Patch
@effect/platform-browser Patch
@effect/platform-bun Patch
@effect/platform-node-shared Patch
@effect/platform-node Patch
@effect/platform Patch
@effect/printer-ansi Patch
@effect/printer Patch
@effect/rpc Patch
@effect/sql-clickhouse Patch
@effect/sql-d1 Patch
@effect/sql-drizzle Patch
@effect/sql-kysely Patch
@effect/sql-libsql Patch
@effect/sql-mssql Patch
@effect/sql-mysql2 Patch
@effect/sql-pg Patch
@effect/sql-sqlite-bun Patch
@effect/sql-sqlite-do Patch
@effect/sql-sqlite-node Patch
@effect/sql-sqlite-react-native Patch
@effect/sql-sqlite-wasm Patch
@effect/sql Patch
@effect/typeclass Patch
@effect/vitest Patch
@effect/workflow Patch
@effect/ai Patch
@effect/ai-amazon-bedrock Patch
@effect/ai-anthropic Patch
@effect/ai-google Patch
@effect/ai-openai Patch
@effect/ai-openrouter Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

"@changesets/cli": "^2.29.4",
"@edge-runtime/vm": "^5.0.0",
"@effect/build-utils": "^0.8.3",
"@effect/docgen": "https://pkg.pr.new/Effect-TS/docgen/@effect/docgen@fd06738",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be reverted :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will need to update the lock file too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, forgot about that.

@tim-smart tim-smart merged commit 7e925ea into Effect-TS:main Jan 20, 2026
9 of 12 checks passed
@github-project-automation github-project-automation bot moved this from Discussion Ongoing to Done in PR Backlog Jan 20, 2026
@github-actions github-actions bot mentioned this pull request Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Array.flatten and pipe losing type information, inducing run time crash

2 participants