TS => MJS: types/map - #1476
Conversation
Migrate fjs/types/map (module + proof) from authored TypeScript to JSDoc-typed JavaScript under the stage-1 TypeScript-to-mjs migration. The module had no authored runtime dependencies, so it moves as a dependency leaf; the proof's only dependency (asserts) was already .f.mjs, so it migrates alongside it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
functionalscript | f9d4490 | Commit Preview URL Branch Preview URL |
Aug 10 2026, 03:55 PM |
Replace the inline /** @type {...} */(...) cast in fjs/types/map/proof.f.mjs with an annotated const declaration, and document the JSDoc-cast hazard (and the migration exception) alongside the existing `as`-assertion guidance in AGENTS.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
o2alexanderfedin
left a comment
There was a problem hiding this comment.
Migration is clean. One doc citation went half-updated.
fjs/types/todo/169.md — extension changed, line numbers and syntax not
The two anchors were correct against the old .f.ts (concat really was at :6, filter at :13). The JSDoc blocks push both down, so after the rename:
| doc says | actually at |
|---|---|
// map/module.f.mjs:6 → concat |
:13 |
// map/module.f.mjs:13 → filter |
:26 |
:13 is now const concat, so the second citation doesn't just miss — it lands on the other helper, which is worse than a stale number.
The fenced block is also still ```ts and reproduces the deleted TypeScript source:
const concat = <T>(x: Iterable<T>, y: Iterable<T>): Iterable<T> => ({where the file now reads
/**
* @template T
* @param {Iterable<T>} x
* @param {Iterable<T>} y
* @returns {Iterable<T>}
*/
const concat = (x, y) => ({Same fix you applied to 193.md in #1471 and to 178.md/186.md in #1472 — re-quote from the new source and re-anchor.
Everything else verified
- The migrated proof is discovered and runs — this was the thing I most wanted to confirm, since a proof that silently stops being collected is a green suite that proves nothing. All three appear in the run:
import("./fjs/types/map/proof.f.mjs").proof.set() / .delete() / .deleteOneOfMany(), all ok, total unchanged at 2355. (.f.mjsproofs aren't new —asserts,asn.1and the threebasenmodules already have them.) - Runtime semantics unchanged; the only edits are type-syntax removal and reflowing
mapSet/mapDeleteonto one line. - Contract preserved:
mapSet: <K, V>(map: ReadonlyMap<K, V>, k: K, v: V) => ReadonlyMap<K, V>andmapDelete: <K, V>(map: ReadonlyMap<K, V>, k: K) => ReadonlyMap<K, V>. @moduleheader survives — the blank line before the firstimportis there, and the header is present inmodule.f.d.mts.- No stale specifier for either
types/mapfile. The one hit that looks like it,fjs/fsm/README.md:110'simport map from './types/map/module.f.ts', is pre-existing illustrative prose that was already wrong — the path doesn't resolve fromfjs/fsm/, andmap.fromEntries/map.setReplaceisordered_map's API, not this module's. Out of scope here. - Annotations load-bearing: against a 0-error baseline, returning the
IterablefrommapDelete→TS2740: Type 'Iterable<[K, V]>' is missing … from type 'ReadonlyMap<K, V>'; swappingmapSet's key/value →TS2322: 'Map<K, V>' is not assignable to 'ReadonlyMap<V, K>'; retypingfilter's predicate as(x: T) => T→TS2322: 'boolean' is not assignable to '[K, V]'. The@param/@returnsform is checked just as tightly as the@typeform. - CHANGELOG entry present with the right
**BREAKING CHANGES:**label.
The AGENTS.md addition on inline /** @type {T} */ (expr) casts reads well and is the natural JSDoc counterpart to the existing "avoid as" rule — and the carve-out for mechanical .f.ts → .f.mjs carry-over keeps it from blocking migrations on redesigns. The deleteOneOfMany rewrite is a good demonstration of the declaration form it recommends.
The concat/filter snippet in fjs/types/todo/169.md still quoted the deleted TypeScript source and used the old .f.ts line numbers, which now point at the wrong helper after the module.f.mjs migration added JSDoc blocks above each function. Re-quote from module.f.mjs and re-anchor to the correct lines (concat:13, filter:26). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
o2alexanderfedin
left a comment
There was a problem hiding this comment.
Citation fixed, both anchors verified against the current head:
| doc | lands on |
|---|---|
// map/module.f.mjs:13 |
const concat = (x, y) => ({ |
// map/module.f.mjs:26 |
const filter = (i, p) => ({ |
The ```js fence and the re-quoted bodies match the source too. Dropping the @template/@param blocks from the excerpt is the right call — the todo is about the shape of the two generator helpers, not their types, and the anchors point at the const lines readers will actually be looking for.
npm test — 2356 pass / 0 fail. Everything from my previous pass still holds: the three types/map proofs are collected from proof.f.mjs and run, the contract is unchanged, the @module header survives, and the annotations are load-bearing under mutation.
Approving.
Pre-existing and about a different module, so not yours to fix and not blocking — but it's four lines below what you just corrected, and it's my own miss: 169.md:26 still reads
(`list/module.f.ts:80`, and its `concat`/`filter` combinators)
fjs/types/list/module.f.ts no longer exists — only module.f.mjs does — and :80 now lands on trampoline, not on the iterable/concat/filter trio the sentence is describing (concat is at :75, iterable at :109, filter at :160). This came from my #1465 sweep, which rewrote the .f.mjs mention two lines above at :24 and missed this one because the path sat inside a parenthetical. Worth picking up whenever someone is next in the file.
Summary
fjs/types/map/module.f.ts->module.f.mjsunder the stage-1TypeScript-to-mjs migration
(
todo/migrate-typescript-to-mjs.md).The module has no authored runtime dependencies, so it qualifies as a
dependency leaf.
proof.f.ts->proof.f.mjs: its only dependency(
asserts/module.f.mjs) is already migrated, so nothing blocks it..f.tspath reference infjs/types/todo/169.md.fjs/types/mapbefore starting.BREAKING CHANGES: importers of
fjs/types/map/module.f.tsandfjs/types/map/proof.f.tsmust use the.f.mjsspecifier instead. No othermodule in the repository currently imports these paths.
Test plan
npx tsc(type check) passesnode ./fjs/module.ts t— full proof suite passes (2355/2355), includingthe migrated
types/mapproofs🤖 Generated with Claude Code
https://claude.ai/code/session_01Y9bV7Civ4LaC6GPsjcgnJY
Generated by Claude Code