Skip to content

fix: separate mapped type from explicit properties in generated response object type#1954

Merged
pmcelhaney merged 6 commits intomainfrom
copilot/fix-mapped-type-and-explicit-properties
Apr 26, 2026
Merged

fix: separate mapped type from explicit properties in generated response object type#1954
pmcelhaney merged 6 commits intomainfrom
copilot/fix-mapped-type-and-explicit-properties

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 25, 2026

TypeScript prohibits mixing explicit properties and a mapped type in the same object literal. When an OpenAPI spec includes a default response alongside explicit status codes, the generator was emitting invalid TypeScript:

// ❌ Before — TypeScript error: mapped type cannot be combined with explicit properties
ResponseBuilderFactory<{
  200: { ... };
  400: { ... };
  [statusCode in Exclude<HttpStatusCode, 200 | 400>]: { ... };
}>

// ✅ After — intersection separates the two
ResponseBuilderFactory<{
  200: { ... };
  400: { ... };
} & {
  [statusCode in Exclude<HttpStatusCode, 200 | 400>]: { ... };
}>

Summary

Generated response types broke tsc when an operation defined both explicit status codes and a default response.

  • responses-type-coder.ts: buildResponseObjectType now partitions entries into explicit (numeric) and mapped ([statusCode in ...]) buckets. When both are present, emits an intersection; otherwise emits a single object as before.
  • responses-type-coder.test.ts: Three new buildResponseObjectType tests cover the intersection path, the explicit-only path, and the mapped-only path.
  • Snapshots updated: 5 Jest snapshots in operation-type-coder.test.ts (×4) and generate.test.ts (×1) updated to match the new intersection output format.
Original Prompt

TypeScript doesn't like this:

export type addPet_$_v3 = OmitValueWhenNever<{
  ...
  response: ResponseBuilderFactory<{
    200: { ... };
    400: { ... };
    422: { ... };
    [statusCode in Exclude<HttpStatusCode, 200 | 400 | 422>]: { ... };
  }>;
  ...
}>;

Manual acceptance tests

  • Generate types from a spec that has both explicit status codes and a default response (e.g. Petstore); confirm the emitted .types.ts file compiles without TypeScript errors
  • Spec with only explicit status codes (no default) generates a single object type with no & intersection
  • Spec with only a default response generates [statusCode in HttpStatusCode]: ... with no intersection
  • Previously broken type (with 200, 400, 422, and default) compiles cleanly under tsc --noEmit

Tasks

  • Partition buildResponseObjectType entries into explicit vs. mapped buckets; emit intersection when both present
  • Add three unit tests covering intersection, explicit-only, and mapped-only cases
  • Update 5 affected Jest snapshots to match new intersection output
  • Add changeset (patch)

…nse object type

TypeScript doesn't allow combining explicit properties (e.g. 200: {...})
with a mapped type ([statusCode in Exclude<HttpStatusCode, ...>]: {...})
in the same object literal. When an OpenAPI spec defines a `default`
response alongside explicit status codes, the generator now emits an
intersection instead:

  { 200: {...}, 400: {...} } & { [statusCode in Exclude<HttpStatusCode, 200 | 400>]: {...} }

Also adds tests for buildResponseObjectType covering the intersection
case, the explicit-only case, and the mapped-only case.

Agent-Logs-Url: https://github.com/counterfact/api-simulator/sessions/486c1732-897a-4987-8e33-6564ad8af31c
Copilot AI changed the title [WIP] Fix combined mapped type and explicit properties issue fix: separate mapped type from explicit properties in generated response object type Apr 25, 2026
Copilot AI requested a review from pmcelhaney April 25, 2026 23:46
@pmcelhaney pmcelhaney marked this pull request as ready for review April 25, 2026 23:50
@pmcelhaney pmcelhaney enabled auto-merge April 25, 2026 23:50
@pmcelhaney
Copy link
Copy Markdown
Collaborator

@copilot unit tests are failing

…d responses

The change to buildResponseObjectType now emits explicit status codes and
the mapped-type default entry as an intersection when both are present.
Update the 5 affected Jest snapshots in operation-type-coder.test.ts and
generate.test.ts to match the new output.

Agent-Logs-Url: https://github.com/counterfact/api-simulator/sessions/f5a4b315-d88f-4ffc-87ed-f482aafafc6f
auto-merge was automatically disabled April 26, 2026 01:41

Head branch was pushed to by a user without write access

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 26, 2026

@copilot unit tests are failing

Fixed in 798f439 — the snapshot tests in operation-type-coder.test.ts (×4) and generate.test.ts (×1) needed to be updated to match the new intersection output format.

@pmcelhaney pmcelhaney enabled auto-merge April 26, 2026 01:46
@pmcelhaney pmcelhaney added this pull request to the merge queue Apr 26, 2026
Merged via the queue into main with commit 8e0d33e Apr 26, 2026
8 of 9 checks passed
@pmcelhaney pmcelhaney deleted the copilot/fix-mapped-type-and-explicit-properties branch April 26, 2026 01:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Don't combine mapped type and explicit properties.

2 participants