Repository navigation
Conversation
A union discriminated on a nested path compiles to a switch on
`data?.a`. That value is also `undefined` when `data` isn't an object
or has no `a` key, so the `undefined` case can't drop the branch's
object domain or its required key the way other cases do. Pruning them
made `type({ k: "1", a: "2" }).or({ k: "3", a: "undefined" })` throw on
primitive input, and `type({ a: "2" }).or({ a: "undefined" })` accept
`0` and `{}`.
Keep branches resolved for an `undefined` case on a nested path as they
are.
Fixes arktypeio#1724
ssalbdivad
added a commit
that referenced
this pull request
Nov 9, 2026
…uthors Each fix below landed on featherduster from a port or an independent fix, but each started from a reasonable community PR against 2.x, and the CHANGELOG thanks every contributor whose work this release supersedes: - #1721 (@RaphaelFakhri): fast-check keeps a regex's flags (#1720) - #1722 (@louisss1016): Temporal values survive a morph / deepClone (#1719) - #1725 (@RClaudiuM): an undefined discriminant case checks its key (#1724) - #1715 (@SynthLuvr): ~standard.jsonSchema.input drops undefined (#1462); only its input half was taken, output keeps routing to fallback.unit #1718 is not credited: 3.0 answers #1469 with jsonSchema meta rather than its bare pattern key. #1705 and #1695 were already thanked. Also notes that a cyclic index signature with no way out now generates shrinking dictionaries instead of overflowing the stack (6f4dd5d).
Draft
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1724
What
Unions discriminated on a nested path no longer drop the object checks from the branch matched by an
undefinedcase:Why
A discriminant on a nested path compiles to
switch (data?.a)(ortypeof data?.afor a domain discriminant). For every other case, matching it meansdatais an object with anakey, sopruneDiscriminantremoves the branch'sdomain: "object"and its required-key check.data?.ais alsoundefinedwhendatais a primitive,nullorundefined, or when the key is missing, so for theundefinedcase those checks are still needed. Without them therequiredcheck ran"k" in 0and threw, and a branch with only the discriminant key compiled toreturn true, accepting any primitive or{}.resolveCasenow leaves the branches (including overlapping ones) unpruned when the case isundefined, as a unit or a domain, and the path isn't empty. Root-levelundefinedcases are exact, so they're still pruned. The jitless path didn't have this bug and is unchanged.Tests
In
ark/type/__tests__/discrimination.test.ts, each with JIT andjitless: truewhere it applies:0,"s",nullandundefinedwith "must be an object", and still checksk{ a: 2 } | { a: undefined }rejects0and{}and accepts{ a: undefined }, also for a two-level path ({ a: { b: ... } })"undefined"case ({ a: string } | { a: undefined } | { a: number }) keepsdomain: "object"and theakey in that caseThe three tests fail on
main(the first throws theTypeErrorfrom the issue) and pass with the change. No existing snapshot changed.Checks run locally (Node 24):
pnpm lint,pnpm typecheckRepo,pnpm test(1816 passing),pnpm testFiles ark/type/__tests__/discrimination.test.tswith type checking,pnpm build,pnpm testV8,pnpm testIntegrationand the@ark/attesttests. I didn't run the benches ortestTsVersionsfromprChecks.mainbranch (based on 326cdce)