Skip to content

feat(core-interfaces): add FluidReadonlyArray type#27747

Open
jenn-le wants to merge 1 commit into
microsoft:mainfrom
jenn-le:add-fluid-readonly-array
Open

feat(core-interfaces): add FluidReadonlyArray type#27747
jenn-le wants to merge 1 commit into
microsoft:mainfrom
jenn-le:add-fluid-readonly-array

Conversation

@jenn-le

@jenn-le jenn-le commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Add FluidReadonlyArray<T> to @fluidframework/core-interfaces as a TypeScript-version-independent equivalent of the built-in ReadonlyArray type, following the same pattern as the existing FluidReadonlyMap and FluidMap types.

This includes stable methods through ES2023 (at(), findLast(), findLastIndex()) but deliberately excludes newer copy-on-write methods (toReversed(), toSorted(), toSpliced(), with()) that our implementations do not yet provide. This ensures Fluid Framework types remain safe to implement without being broken by TypeScript updates that add new members to ReadonlyArray.

The type is introduced at @beta and re-exported from fluid-framework. It will be used in a follow-up PR to replace the extends ReadonlyArray<T> in ReadonlyArrayNode/TreeArrayNode.

Reviewer Guidance

Reviewer guidance wiki

  • The new FluidReadonlyArray interface is in packages/common/core-interfaces/src/fluidArray.ts
  • Shared type test utilities were extracted to src/test/types/typeTestUtils.ts (also used by existing fluidMapTypes.ts)
  • Type tests verify assignability relationships under the repo's ES2020 lib setting

Copilot AI review requested due to automatic review settings July 23, 2026 05:05
@jenn-le
jenn-le requested review from a team as code owners July 23, 2026 05:05
@github-actions github-actions Bot added area: framework Framework is a tag for issues involving the developer framework. Eg Aqueduct area: tools area: repo Repo related work area: website public api change Changes to a public API changeset-present base: main PRs targeted against main branch labels Jul 23, 2026
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Hi! Thank you for opening this PR. Want me to review it?

Based on the diff (690 lines, 12 files), I've queued these reviewers:

  • Correctness — logic errors, race conditions, lifecycle issues
  • Security — vulnerabilities, secret exposure, injection
  • API Compatibility — breaking changes, release tags, type design
  • Performance — algorithmic regressions, memory leaks
  • Testing — coverage gaps, hollow tests

How this works

  • Adjust the reviewer set by ticking/unticking boxes above. Reviewer toggles alone don't trigger anything.

  • Tick Start review below to dispatch the review fleet.

  • After review finishes, tick Start review again to request another run — it auto-resets after each dispatch.

  • This comment updates as new commits land; your reviewer selections are preserved.

  • Start review

Copilot AI left a comment

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.

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

@jenn-le
jenn-le force-pushed the add-fluid-readonly-array branch 2 times, most recently from 2583321 to 5cdf764 Compare July 23, 2026 18:10
@jenn-le jenn-le changed the title feat(core-interfaces): Add FluidReadonlyArray type feat(core-interfaces): add FluidReadonlyArray type Jul 23, 2026
@jenn-le
jenn-le force-pushed the add-fluid-readonly-array branch from 7e19418 to 2c8b5d2 Compare July 23, 2026 20:55
Add FluidReadonlyArray<T> as a TypeScript-version-independent equivalent
of ReadonlyArray, following the pattern of FluidReadonlyMap and FluidMap.
Includes stable methods through ES2023 (at, findLast, findLastIndex) but
excludes copy-on-write methods (toReversed, toSorted, toSpliced, with)
that our implementations do not yet provide.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@jenn-le
jenn-le force-pushed the add-fluid-readonly-array branch from 2c8b5d2 to 49a0424 Compare July 23, 2026 20:56
@github-actions

Copy link
Copy Markdown
Contributor

🔗 No broken links found! ✅

Your attention to detail is admirable.

linkcheck output

1: starting server using command "npm run serve -- --no-open"
and when url "[ 'http://127.0.0.1:3000' ]" is responding with HTTP status code 200
running tests using command "npm run check-links"


> fluid-framework-website@0.0.0 serve
> docusaurus serve --no-open

[SUCCESS] Serving "build" directory at: http://localhost:3000/

> fluid-framework-website@0.0.0 check-links
> linkcheck http://localhost:3000 --skip-file skipped-urls.txt

Crawling...

Stats:
  306247 links
    1957 destination URLs
    2213 URLs ignored
       0 warnings
       0 errors


@github-actions

Copy link
Copy Markdown
Contributor

Bundle size comparison

Base commit: b053be3ea64d10d431e2f5a44391b2d18a5bc505
Head commit: 49a0424129021c8eaf22f4441d66a6b55f9a4138

Notable changes

No bundles changed by ≥ 500 bytes parsed.

Per-bundle deltas

@fluid-example/bundle-size-tests

  • azureClient.js: parsed 620317 → 620373 (+56), gzip 165071 → 165117 (+46)
  • odspClient.js: parsed 593043 → 593099 (+56), gzip 159171 → 159214 (+43)
  • aqueduct.js: parsed 526806 → 526841 (+35), gzip 140956 → 140986 (+30)
  • fluidFramework.js: parsed 398444 → 398465 (+21), gzip 113068 → 113079 (+11)
  • sharedTree.js: parsed 387831 → 387845 (+14), gzip 110466 → 110472 (+6)
  • containerRuntime.js: parsed 305156 → 305170 (+14), gzip 83445 → 83452 (+7)
  • sharedString.js: parsed 175984 → 175991 (+7), gzip 49445 → 49452 (+7)
  • experimentalSharedTree.js: parsed 160798 → 160798 (0), gzip 45804 → 45804 (0)
  • matrix.js: parsed 159845 → 159852 (+7), gzip 45411 → 45418 (+7)
  • loader.js: parsed 145256 → 145270 (+14), gzip 39063 → 39076 (+13)
  • odspDriver.js: parsed 104329 → 104350 (+21), gzip 32625 → 32635 (+10)
  • directory.js: parsed 66616 → 66623 (+7), gzip 18532 → 18540 (+8)
  • 748.js: parsed 58793 → 58793 (0), gzip 17827 → 17827 (0)
  • map.js: parsed 46709 → 46716 (+7), gzip 14310 → 14317 (+7)
  • odspPrefetchSnapshot.js: parsed 45642 → 45656 (+14), gzip 15277 → 15284 (+7)
  • 985.js: parsed 44491 → 44491 (0), gzip 13726 → 13726 (0)
  • summarizerDelayLoadedModule.js: parsed 30749 → 30749 (0), gzip 7753 → 7753 (0)
  • socketModule.js: parsed 26476 → 26483 (+7), gzip 7887 → 7894 (+7)
  • createNewModule.js: parsed 12480 → 12480 (0), gzip 4786 → 4786 (0)
  • summaryModule.js: parsed 3797 → 3797 (0), gzip 1860 → 1860 (0)
  • connectionState.js: parsed 724 → 724 (0), gzip 429 → 429 (0)
  • sharedTreeAttributes.js: parsed 666 → 673 (+7), gzip 433 → 441 (+8)
  • debugAssert.js: parsed 429 → 429 (0), gzip 299 → 299 (0)
  • FluidFramework-HashFallback.js: parsed 422 → 422 (0), gzip 316 → 316 (0)

isAssignableTo<readonly string[], FluidReadonlyArray<string>>
>;

// FluidReadonlyArray is NOT assignable to ReadonlyArray due to minor structural differences

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 makes adopting this type a breaking chain which could be quite problematic for users to adopt.

I think we need to fix that.

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.

I think the main requirement for this change is that we make this true: as long as its not passing, we don't have a good way to validate that we got our interface correct, and it will break customers which uses our arrays as readonly arrays (which used to be supported) even with typescript configurations where that worked before.

What we want to get out of this change is to keep such users working, but make the case where they change their tsconfig and start getting errors to report the errors in their code and not ours.

>;

// FluidReadonlyArray is NOT assignable to ReadonlyArray due to minor structural differences
// in Symbol.unscopables typing. This is acceptable — the important direction is that

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.

Can you put the sentence breaks not in the middle of lines, it makes commenting on sentences hard.


// FluidReadonlyArray is NOT assignable to ReadonlyArray due to minor structural differences
// in Symbol.unscopables typing. This is acceptable — the important direction is that
// native arrays (which ARE ReadonlyArray) remain assignable to FluidReadonlyArray under ES2023+.

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 is something we specifically do not support users doing, so having it work is probably more harmful then useful. Our type is sealed documenting that this is no allowed: we want this type to be one which only we are allowed to implement it so we can add things to it as needed, such as new API s that get added in 2-35 or whatever which would break code assigning 2023 arrays to our sealed type.


// Native mutable Array is NOT assignable to FluidReadonlyArray under ES2020
// (missing at/findLast/findLastIndex).
declare type _array_to_fluidReadonlyArray = requireFalse<

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, and the above non-assignability checks are not very useful. There are tons of reasons types might not be assignable ( if we implemented our array type as something totally wrong, like number those tests would all still pass, and give 0 useful information).

Additionally this test really tells us pretty much nothing, and also will break when we update to a newer es standard, which we plan to do soon. A test which doesn't validate anything we care about, and will have to be modified in the future has negative value.


/**
* Compile-time type utilities for manual type tests in this package.
* These mirror the pattern used in the auto-generated type test files.

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.

Can't this package just import those the same way the generated type tests do?

* Licensed under the MIT License.
*/

import type { FluidIterableIterator, FluidReadonlyArray } from "../../index.js";

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.

Looks like these are the only test changes here: you should also update the tests in import-testing which are skipped due to the issue you are fixing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: framework Framework is a tag for issues involving the developer framework. Eg Aqueduct area: repo Repo related work area: tools area: website base: main PRs targeted against main branch changeset-present public api change Changes to a public API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants