Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,29 @@ Avoid `as` type assertions (except `as const`). Treat them like `unsafe` in Rust
justified. They silence the type checker and hide real bugs; if a cast is needed,
it usually means the types or the code structure should be improved instead.

The JSDoc equivalent, an inline `/** @type {T} */ (expr)` cast, carries the same
hazard and the same rule: avoid it. Prefer annotating a separate `const`
declaration instead of casting an expression inline —

```js
/** @type {ReadonlyMap<string, number>} */
const empty = new Map()
```

rather than

```js
mapSet(/** @type {ReadonlyMap<string, number>} */ (new Map()), 'a', 1)
```

— because the declaration form documents the variable's intended type and lets
the compiler check the initializer against it (closer to `satisfies`), while the
inline form silently overrides whatever the compiler inferred, exactly like `as`.
An exception applies when the original TypeScript source used `as`: a mechanical
`.f.ts` → `.f.mjs` migration may carry the assertion over as an inline
`@type`-cast rather than block on a redesign, but should still prefer the
declaration form when it is a straightforward rewrite.

#### Avoid type predicates

Avoid TypeScript type predicates (`(x: T): x is U`). They are error-prone: the
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ history.

## Unreleased

- **BREAKING CHANGES:** `fjs/types/map` migrates from authored TypeScript
(`.f.ts`) to JSDoc-typed JavaScript (`.f.mjs`) under the stage-1
TypeScript-to-mjs migration — importers must use the `.f.mjs` specifier
[#1476](https://github.com/functionalscript/functionalscript/pull/1476)
- **BREAKING CHANGES:** `fjs/types/btree` migrates from authored TypeScript
(`.f.ts`) to JSDoc-typed JavaScript (`.f.mjs`) under the stage-1
TypeScript-to-mjs migration — importers must use the `.f.mjs` specifier
Expand Down
42 changes: 42 additions & 0 deletions fjs/types/map/module.f.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Persistent map operations built on ordered collections.
*
* @module
*/

/**
* @template T
* @param {Iterable<T>} x
* @param {Iterable<T>} y
* @returns {Iterable<T>}
*/
const concat = (x, y) => ({
*[Symbol.iterator]() {
yield* x
yield* y
}
})

/**
* @template T
* @param {Iterable<T>} i
* @param {(x: T) => boolean} p
* @returns {Iterable<T>}
*/
const filter = (i, p) => ({
*[Symbol.iterator]() {
for (const x of i) {
if (p(x)) { yield x }
}
}
})

/**
* @type {<K, V>(map: ReadonlyMap<K, V>, k: K, v: V) => ReadonlyMap<K, V>}
*/
export const mapSet = (map, k, v) => new Map(concat(map, [[k, v]]))

/**
* @type {<K, V>(map: ReadonlyMap<K, V>, k: K) => ReadonlyMap<K, V>}
*/
export const mapDelete = (map, k) => new Map(filter(map, ([xk]) => xk !== k))
25 changes: 0 additions & 25 deletions fjs/types/map/module.f.ts

This file was deleted.

6 changes: 4 additions & 2 deletions fjs/types/map/proof.f.ts → fjs/types/map/proof.f.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mapSet, mapDelete } from './module.f.ts'
import { mapSet, mapDelete } from './module.f.mjs'
import { assertEq } from '../../asserts/module.f.mjs'

export const proof = {
Expand All @@ -13,7 +13,9 @@ export const proof = {
assertEq(map.size, 0, 'error')
},
deleteOneOfMany: () => {
const m0 = mapSet(new Map<string, number>(), 'a', 1)
/** @type {ReadonlyMap<string, number>} */
const empty = new Map()
const m0 = mapSet(empty, 'a', 1)
const m1 = mapSet(m0, 'b', 2)
const result = mapDelete(m1, 'a')
assertEq(result.get('b'), 2)
Expand Down
14 changes: 7 additions & 7 deletions fjs/types/todo/169.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
**Priority:** P3
**Status:** open

`fjs/types/map/module.f.ts` defines two private generator helpers solely to feed
`new Map(...)`:
`fjs/types/map/module.f.mjs` defines two private generator helpers solely to
feed `new Map(...)`:

```ts
// map/module.f.ts:6
const concat = <T>(x: Iterable<T>, y: Iterable<T>): Iterable<T> => ({
```js
// map/module.f.mjs:13
const concat = (x, y) => ({
*[Symbol.iterator]() { yield* x; yield* y }
})
// map/module.f.ts:13
const filter = <T>(i: Iterable<T>, p: (x: T) => boolean): Iterable<T> => ({
// map/module.f.mjs:26
const filter = (i, p) => ({
*[Symbol.iterator]() { for (const x of i) { if (p(x)) { yield x } } }
})

Expand Down
Loading