✅ Assert the shape each handler receives
A handler's `expectTypeOf(shape)` only proved the type the compiler inferred; nothing observed the argument `dispatch` passed. Passing `String(shape)` at the call site therefore kept the whole suite green while breaking every key whose property name differs from its value (`true`, `null`, `1`). Pair each handler expectation with a runtime assertion: `assert.equal` where a handler runs for one shape, the disjunction over the set a `_` fallback accepts where it runs for several. Where the exact value matters the fallback returns its shape verbatim and the call site asserts it; a widening pattern absorbs the remainder type into the return union, so the claim stays strict-free. The mutation above now fails 10 of the 33 tests. Rule: CONTRIBUTING.md, rationale: development/testing.md § Handler arguments.
This commit is contained in:
1 parent
aa6d71076c
commit
9e03c52473
3 files changed
+109
-11
No files matched your search
@@ -37,6 +37,40 @@ in
|
||||
build step, and the runner relies on the `.ts` import-extension convention (see
|
||||
[tooling.md](./tooling.md#source-imports-use-ts-extensions)).
|
||||
|
||||
## Handler arguments
|
||||
|
||||
#### Decision (2026-09)
|
||||
|
||||
A handler's `expectTypeOf(shape)` is always paired with an assertion on the
|
||||
argument `dispatch` actually passed: `assert.equal` where the handler runs for
|
||||
one shape, `assert.ok(s === … || s === …)` over the set a `_` fallback accepts
|
||||
(`assert` is imported as `strict`, so each comparison is `Object.is`). Where a
|
||||
test should also prove that the _exact_ value reached the handler unchanged,
|
||||
the fallback returns the shape verbatim and the call site asserts it.
|
||||
|
||||
#### Why
|
||||
|
||||
- The parameter's type is what the compiler inferred from the pattern; the
|
||||
argument is what the runtime passed. Only the second can drift, and the keys
|
||||
whose property name differs from their value (`true`, `null`, `1`) are
|
||||
exactly where it can — see [library.md](./library.md).
|
||||
- `String(shape)` at the call site keeps every type expectation and every
|
||||
return-value assertion green; the argument assertions fail (10 of the 33
|
||||
tests). Without them the suite never looks at the passed argument.
|
||||
- Returning the shape verbatim costs a widening pattern nothing: the remainder
|
||||
type joins the union of handler returns in place of a marker literal, so the
|
||||
test still shows the widening it is named for.
|
||||
|
||||
#### Rejected
|
||||
|
||||
- A recorded `unknown[]` of every fallback call compared with `deepEqual`:
|
||||
strong, but it couples the assertion to call order, and the sink sits three
|
||||
blocks away from the value it observes.
|
||||
- `typeof` checks: they cannot separate `2` from its key text `"2"`, which is
|
||||
the drift a fallback with a numeric remainder can hit.
|
||||
- One expected value asserted inline in a fallback: its argument is a _set_ of
|
||||
shapes, so only the disjunction holds on every call.
|
||||
|
||||
## AAA ordering
|
||||
|
||||
The rule is in
|
||||
|
||||
Reference in new issue
Block a user