From 4f2947152e79cb657fb6c27f5d02b0d51da6359d Mon Sep 17 00:00:00 2001 From: Giulio Canti Date: Thu, 4 Jun 2026 19:00:30 +0200 Subject: [PATCH] Emit `additionalProperties: false` for records with string keys and `Schema.Never` values --- .../json-schema-never-additional-properties.md | 5 +++++ packages/effect/src/JSONSchema.ts | 5 ++++- packages/effect/test/Schema/JSONSchema.test.ts | 12 ++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .changeset/json-schema-never-additional-properties.md diff --git a/.changeset/json-schema-never-additional-properties.md b/.changeset/json-schema-never-additional-properties.md new file mode 100644 index 00000000000..e95f825d68d --- /dev/null +++ b/.changeset/json-schema-never-additional-properties.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Emit `additionalProperties: false` for records with string keys and `Schema.Never` values. diff --git a/packages/effect/src/JSONSchema.ts b/packages/effect/src/JSONSchema.ts index 4b5220eb434..c4ec30cf49b 100644 --- a/packages/effect/src/JSONSchema.ts +++ b/packages/effect/src/JSONSchema.ts @@ -843,7 +843,7 @@ function go( const parameter = is.parameter switch (parameter._tag) { case "StringKeyword": { - output.additionalProperties = go( + const additionalProperties = go( pruned, $defs, "handle-identifier", @@ -852,6 +852,9 @@ function go( "handle-annotation", errors ) + output.additionalProperties = isNeverWithoutCustomAnnotations(additionalProperties) + ? false + : additionalProperties break } case "TemplateLiteral": { diff --git a/packages/effect/test/Schema/JSONSchema.test.ts b/packages/effect/test/Schema/JSONSchema.test.ts index e3eaec514b3..be580edbe53 100644 --- a/packages/effect/test/Schema/JSONSchema.test.ts +++ b/packages/effect/test/Schema/JSONSchema.test.ts @@ -2149,6 +2149,18 @@ details: Cannot encode Symbol(effect/Schema/test/a) key to JSON Schema` }) }) + it("Record(string, never)", () => { + const jsonSchema = expectJSONSchema(Schema.Record({ key: Schema.String, value: Schema.Never }), { + "type": "object", + "properties": {}, + "required": [], + "additionalProperties": false + }) + const validate = getAjvValidate(jsonSchema) + assertTrue(validate({})) + assertFalse(validate({ a: null })) + }) + it("Record('a' | 'b', number)", () => { expectJSONSchemaAnnotations( Schema.Record(