Repository navigation
Add option to generate never for not schemas that accept everything - #1844
Conversation
NotSchemaParser returned any for every not schema, so not: {} and
not: true came out as any even though no value can satisfy them. The
common "exactly one of these properties" pattern lost its meaning.
Return never for those two forms. Other not schemas still generate any
because TypeScript cannot express them.
Fixes acacode#1821
🦋 Changeset detectedLatest commit: ca0f680 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/schema-parser/complex-schema-parsers/not.ts">
<violation number="1" location="src/schema-parser/complex-schema-parsers/not.ts:8">
P2: This exact-equality check misses annotation-only schemas such as `not: { description: "..." }`. Annotations impose no validation constraints, so their negation is also impossible, yet this returns `any` and allows invalid values; detect schemas with no validation keywords rather than only `{}`.</violation>
</file>
Reply to a comment to ask cubic a question or push back. It learns from your replies.
View guided diff | Re-trigger cubic
| return this.config.Ts.Keyword.Any; | ||
| // `{}` and `true` accept every value, so negating them leaves no valid value. | ||
| const allowsNothing = | ||
| this.schema.not === true || isEqual(this.schema.not, {}); |
There was a problem hiding this comment.
P2: This exact-equality check misses annotation-only schemas such as not: { description: "..." }. Annotations impose no validation constraints, so their negation is also impossible, yet this returns any and allows invalid values; detect schemas with no validation keywords rather than only {}.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/schema-parser/complex-schema-parsers/not.ts, line 8:
<comment>This exact-equality check misses annotation-only schemas such as `not: { description: "..." }`. Annotations impose no validation constraints, so their negation is also impossible, yet this returns `any` and allows invalid values; detect schemas with no validation keywords rather than only `{}`.</comment>
<file context>
@@ -1,7 +1,14 @@
- return this.config.Ts.Keyword.Any;
+ // `{}` and `true` accept every value, so negating them leaves no valid value.
+ const allowsNothing =
+ this.schema.not === true || isEqual(this.schema.not, {});
+
+ return allowsNothing
</file context>
Changing the generated type from any to never can break existing code, so the new output is now opt-in through a generate param and a CLI flag.
|
Thank you! |
Fixes #1821
not: {}generatesany. No value can satisfy that schema, soneverdescribes it better. With the schema from the issue, a union that allows exactly one of two properties comes out withexternalId?: anyandinternalId?: any, so TypeScript accepts objects that set both.Changing that output can break existing code, so after review it's now behind a new option:
emptyNotAsNeveringenerateApi,--empty-not-as-neveron the CLI. It is off by default and generated output doesn't change unless you turn it on.With it on,
not: {}andnot: truegeneratenever.trueis not in the issue, but it accepts every value just like{}. Any othernotstill generatesany, including annotation-only schemas such asnot: { description: "..." }. The changeset is now a minor bump.What I ran, on Node 22:
tests/spec/not-empty-schemahas two tests. With the old parser, the option-on test fails atexpect(content).toContain("externalId?: never;"). The default-off test passes with both.vitest run: 306 tests in 101 files pass, with no snapshot changes.biome checkon the changed files reports one error,organizeImportsattypes/index.ts:1:1. This PR doesn't touch those lines.What I did not run:
bun run build, or Node 20, 24 and 25.Summary by cubic
Fixes #1821 by adding an opt-in
emptyNotAsNeveroption (--empty-not-as-never) that generatesneverinstead ofanyfornot: {}andnot: trueschemas, which accept every value and so can never be satisfied. PreviouslyNotSchemaParseralways returnedany, letting TypeScript accept objects in the "exactly one of these properties" pattern that set both. The option is off by default, so existing generated output is unchanged unless it's enabled. Othernotschemas still generateanybecause TypeScript cannot express them. Adds a changeset and a spec test.Written for commit ca0f680. Summary will update on new commits.