From 0d6a3f1b9b4f4cd40cfe9325d9b716d236686798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Fri, 18 Sep 2026 23:48:59 +0000 Subject: [PATCH] :white_check_mark: Cover the dispatch throw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An open universe (`getMatcher()`) types its handler map as an index signature, so a runtime map with fewer keys still satisfies the exhaustive overload. Calling the matcher with a missing shape reaches the dispatch guard and throws — no cast needed. --- src/primitive.test.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/primitive.test.ts b/src/primitive.test.ts index 6b1c9f8..3c445fe 100644 --- a/src/primitive.test.ts +++ b/src/primitive.test.ts @@ -326,6 +326,21 @@ test("getMatcherW factory rejects patterns outside its contract", () => { factory({ x: () => 1 as const }); }); +// ============================================================================ +// Dispatch — runtime behavior +// ============================================================================ + +test("getMatcher: an unhandled shape throws without a fallback", () => { + // Arrange — an open universe types its handler map as an index signature, + // so the type system cannot prove the runtime map is exhaustive. + const handlers: Record number> = { a: () => 1 }; + const matcher = getMatcher()(handlers); + + // Act / Assert + assert.equal(matcher("a"), 1); + assert.throws(() => matcher("b"), /Unhandled shape: b/); +}); + // ============================================================================ // Autocomplete — the language server is the oracle, not the type system // ============================================================================