From 2230ffbb27132112db80c1ebb14067ef04790fce Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Tue, 20 Oct 2026 19:25:18 -0500 Subject: [PATCH] Check the optional-record path test's cast at the cast The test from #1548 casts JSON.parse to Partial into a block-local const, which continues as its parsed value since #1561, as in Node. The path messages are now pinned with the cast passed to a typed parameter, which is checked at the cast, and the block-local form is pinned against Node. --- tests/harness/dyncheck.test.ts | 37 ++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 2633cc8158..441a029f4c 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -312,10 +312,11 @@ console.log("unreachable", c.host); // `Partial` makes every member an `X | undefined` union. A present // object that fails X used to report only the union's own path // ("expected object | undefined at $.order, got object"); the record - // arm's builder now reports where inside it the value fails. - const r = await compileAndRun( - "optional-record-deep", - `interface Order { + // arm's builder now reports where inside it the value fails. The cast + // is passed straight to a typed parameter, so it is checked at the + // cast: one that initializes a block-local binding continues as its + // parsed value instead (checked-cast fallback), as in Node. + const types = `interface Order { owner: { id: string; plan: { tier: string } }; total: number; } @@ -326,10 +327,15 @@ const texts = [ '{"order":{"owner":{"id":"u1","plan":{"tier":"pro"}},"total":3},"tags":["a",2]}', '{"order":5}', ]; +`; + const r = await compileAndRun( + "optional-record-deep", + `${types}function show(e: Partial): void { + console.log("ok", e.order?.owner.id); +} for (const text of texts) { try { - const e = JSON.parse(text) as Partial; - console.log("ok", e.order?.owner.id); + show(JSON.parse(text) as Partial); } catch (err) { if (err instanceof TypeError) console.log(err.message); } @@ -346,6 +352,25 @@ for (const text of texts) { "", ].join("\n"), ); + const fallback = await compileAndRun( + "optional-record-deep-fallback", + `${types}for (const text of texts) { + try { + const e = JSON.parse(text) as Partial; + console.log("ok", e.order?.owner.id); + } catch (err) { + if (err instanceof TypeError) console.log(err.message); + } +} +`, + "ts", + true, + ); + expect(fallback.stdout).toBe( + ["ok u1", "ok 7", "ok u1", "Cannot read properties of undefined (reading 'id')", ""].join( + "\n", + ), + ); }); test("JSON null matches nothing", async () => {