diff --git a/development/library.md b/development/library.md index 967feb9..7c6b5fe 100644 --- a/development/library.md +++ b/development/library.md @@ -106,9 +106,11 @@ offers `true`, `false`, `null`, `undefined` by name (verified over LSP). #### Why -- Runtime dispatch is unchanged in effect: `handlers[true]` already coerces to - `"true"`. `dispatch` wraps the index in `String()` only because TypeScript - forbids indexing with `boolean`/`null`/`undefined` (`TS2538`). +- Runtime dispatch indexes with the raw `shape`; `handlers[true]` coerces to + `"true"` at runtime exactly as `String` would. The `shape as string | number` + assertion only placates `TS2538` and buys the number fast path (an explicit + `String()` defeats V8's numeric-key path: measured ~2× on number-keyed + dispatch). - `symbol`/`bigint`/`NaN`/`-0` are rejected, and a member colliding with its stringification is unguarded: user-facing, stated once in [README § Caveats](../README.md#caveats). diff --git a/src/primitive.ts b/src/primitive.ts index 2c27b56..7919d2c 100644 --- a/src/primitive.ts +++ b/src/primitive.ts @@ -109,11 +109,17 @@ type HandlerMap = Record | undefined>; const dispatch = (handlers: HandlerMap, fallback?: UnaryFn) => (shape: Matchable): unknown => - // `handlers[true]` already coerces to the `"true"` property at - // runtime; `String` is here only because TypeScript forbids - // indexing with `boolean`/`null`/`undefined` (TS2538). + // `handlers[true]` already coerces to the `"true"` property at runtime, + // identical to `handlers[String(shape)]`, so indexing with `shape` + // directly is sound: `shape` is a facade-checked universe member and + // `PatternKey` only ever produces valid property keys. The assertion is + // needed solely because TypeScript forbids indexing with + // `boolean`/`null`/`undefined` (TS2538); it buys the number fast path. ( - handlers[String(shape)] ?? + handlers[ + // oxlint-disable-next-line typescript/no-unsafe-type-assertion + shape as string | number + ] ?? fallback ?? (() => { throw new Error(`Unhandled shape: ${String(shape)}`);