Skip to content

fix(typespec-ts): use void instead of undefined in optional body response return types#4804

Merged
v-jiaodi merged 7 commits into
mainfrom
copilot/update-response-code-204-status
Jul 6, 2026
Merged

fix(typespec-ts): use void instead of undefined in optional body response return types#4804
v-jiaodi merged 7 commits into
mainfrom
copilot/update-response-code-204-status

Conversation

Copilot AI commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

When an operation returns either a body (200) or an empty body (204), the emitter was generating Promise<KeyValue | undefined> instead of the semantically correct Promise<KeyValue | void>.

Changes

  • operation-helpers.ts: Replace | undefined with | void in 3 locations where response.optional drives the union return type — covers both getDeserializePrivateFunction and getOperationFunction (with/without response headers)
  • Test snapshots (deserializeEmptyBody.md, armPatchWithUnionResponse.md): Updated expected output accordingly
  • Baseline (previewVersion/src/index.d.ts): Regenerated to reflect new void union type

Before / After

// Before
export async function _deleteKeyValueDeserialize(
  result: PathUncheckedResponse,
): Promise<KeyValue | undefined> { ... }

// After
export async function _deleteKeyValueDeserialize(
  result: PathUncheckedResponse,
): Promise<KeyValue | void> { ... }

The implementation body continues to return undefined in the empty-body branch (result.body ? deserializer(result.body) : undefined), which is valid since undefined is assignable to void.

…types

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>
@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:typescript Issues for @azure-tools/typespec-ts emitter label Jul 2, 2026
Copilot AI changed the title [WIP] Update response code generation for 204 empty body fix(typespec-ts): use void instead of undefined in optional body response return types Jul 2, 2026
Copilot AI requested a review from v-jiaodi July 2, 2026 09:50
@v-jiaodi v-jiaodi marked this pull request as ready for review July 3, 2026 03:51
@azure-sdk-automation

Copy link
Copy Markdown
Contributor

All changed packages have been documented.

  • @azure-tools/typespec-ts
Show changes

@azure-tools/typespec-ts - fix ✏️

Fix return type for operations with optional body response: use void instead of undefined in union return types (e.g. Promise<KeyValue | void> instead of Promise<KeyValue | undefined>)

@pkg-pr-new

pkg-pr-new Bot commented Jul 3, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@azure-tools/typespec-ts@4804

commit: 860cdf0

@azure-sdk-automation

Copy link
Copy Markdown
Contributor

You can try these changes here

🛝 Playground 🌐 Website

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

⚡ Benchmark Results

⚠️ 15 metric(s) regressed above the +5% threshold:

Metric Baseline Current Change
total 🔴 969.5ms 🔴 1.04s +7.1% 🔴
loader 🟡 292.3ms 🟡 321.7ms +10.0% 🔴
checker 🟡 349.1ms 🟡 371.5ms +6.4% 🔴
 ↳ validation/@typespec/http 🟡 14.9ms 🟡 16.0ms +7.1% 🔴
linter 🟡 206.3ms 🟡 220.4ms +6.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 25.5ms 🔴 27.8ms +9.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 26.7ms 🔴 29.2ms +9.3% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 32.0ms 🔴 34.5ms +7.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 31.3ms 🔴 33.5ms +6.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 20.2ms 🔴 22.2ms +9.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 18.8ms 🔴 20.7ms +10.2% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 28.5ms 🔴 31.0ms +9.0% 🔴
 ↳ emit/@azure-tools/typespec-python 🔴 2.19s 🔴 2.30s +5.1% 🔴
 ↳ emit/@typespec/openapi3 🟢 103.4ms 🟢 109.6ms +6.0% 🔴
 ↳ emit/@typespec/openapi3/compute 🟢 89.7ms 🟢 95.2ms +6.1% 🔴
Full details – comparing 1a5aa81 vs baseline rolling-baseline-609e362-a18f78b (rolling baseline (20 main runs))
Metric Baseline Current Change
total 🔴 969.5ms 🔴 1.04s +7.1% 🔴
loader 🟡 292.3ms 🟡 321.7ms +10.0% 🔴
resolver 🟢 38.9ms 🟢 39.3ms +0.9%
checker 🟡 349.1ms 🟡 371.5ms +6.4% 🔴
validation 🟢 82.8ms 🟢 85.3ms +3.1%
 ↳ validation/@azure-tools/typespec-azure-core 🟡 12.1ms 🟡 13.1ms +8.1%
 ↳ validation/@typespec/http 🟡 14.9ms 🟡 16.0ms +7.1% 🔴
 ↳ validation/@typespec/rest 🟢 1.6ms 🟢 1.6ms -0.6%
 ↳ validation/@typespec/versioning 🔴 50.3ms 🔴 50.8ms +1.1%
 ↳ validation/compiler 🟢 3.8ms 🟢 3.9ms +2.5%
linter 🟡 206.3ms 🟡 220.4ms +6.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/auth-required 🟢 0.1ms 🟢 0.1ms +5.8%
 ↳ linter/@azure-tools/typespec-azure-core/bad-record-type 🟢 0.6ms 🟢 0.6ms +1.1%
 ↳ linter/@azure-tools/typespec-azure-core/byos 🟢 8.0ms 🟢 8.4ms +4.7%
 ↳ linter/@azure-tools/typespec-azure-core/casing-style 🟢 1.4ms 🟢 1.4ms +2.8%
 ↳ linter/@azure-tools/typespec-azure-core/composition-over-inheritance 🟢 0.2ms 🟢 0.2ms +2.7%
 ↳ linter/@azure-tools/typespec-azure-core/documentation-required 🟢 1.9ms 🟢 2.0ms +3.5%
 ↳ linter/@azure-tools/typespec-azure-core/friendly-name 🟢 1.4ms 🟢 1.4ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-core/key-visibility-required 🟢 0.4ms 🟢 0.4ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-core/known-encoding 🟢 0.5ms 🟢 0.5ms +8.7%
 ↳ linter/@azure-tools/typespec-azure-core/long-running-polling-operation-required 🟢 0.8ms 🟢 0.8ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-case-mismatch 🟢 0.7ms 🟢 0.7ms +1.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-closed-literal-union 🟢 1.0ms 🟢 0.9ms -0.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-enum 🟢 0.2ms 🟢 0.2ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-error-status-codes 🟢 0.3ms 🟢 0.3ms +1.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-explicit-routes-resource-ops 🟢 0.2ms 🟢 0.2ms +1.9%
 ↳ linter/@azure-tools/typespec-azure-core/no-format 🟢 0.8ms 🟢 0.8ms +2.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-generic-numeric 🟢 0.8ms 🟢 0.8ms +1.8%
 ↳ linter/@azure-tools/typespec-azure-core/no-header-explode 🔴 25.5ms 🔴 27.8ms +9.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-legacy-usage 🟢 1.9ms 🟢 2.1ms +8.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-multiple-discriminator 🟢 0.2ms 🟢 0.2ms +10.4%
 ↳ linter/@azure-tools/typespec-azure-core/no-nullable 🟢 0.4ms 🟢 0.4ms +6.0%
 ↳ linter/@azure-tools/typespec-azure-core/no-offsetdatetime 🟢 1.9ms 🟢 2.0ms +6.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-openapi 🟢 2.3ms 🟢 2.3ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-private-usage 🟢 3.0ms 🟢 3.2ms +6.1%
 ↳ linter/@azure-tools/typespec-azure-core/no-query-explode 🔴 26.7ms 🔴 29.2ms +9.3% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-response-body 🔴 32.0ms 🔴 34.5ms +7.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/no-rest-library-interfaces 🟢 0.1ms 🟢 0.1ms +5.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-route-parameter-name-mismatch 🟢 7.3ms 🟢 7.9ms +8.3%
 ↳ linter/@azure-tools/typespec-azure-core/no-rpc-path-params 🟢 0.4ms 🟢 0.4ms +5.6%
 ↳ linter/@azure-tools/typespec-azure-core/no-string-discriminator 🟢 0.1ms 🟢 0.1ms +7.2%
 ↳ linter/@azure-tools/typespec-azure-core/no-unknown 🟢 0.3ms 🟢 0.4ms +7.5%
 ↳ linter/@azure-tools/typespec-azure-core/no-unnamed-union 🟢 0.8ms 🟢 0.8ms +2.6%
 ↳ linter/@azure-tools/typespec-azure-core/operation-missing-api-version 🟢 0.4ms 🟢 0.4ms +0.6%
 ↳ linter/@azure-tools/typespec-azure-core/request-body-problem 🟢 0.4ms 🟢 0.4ms +1.1%
 ↳ linter/@azure-tools/typespec-azure-core/require-versioned 🟢 0.1ms 🟢 0.1ms +5.9%
 ↳ linter/@azure-tools/typespec-azure-core/response-schema-problem 🔴 31.3ms 🔴 33.5ms +6.9% 🔴
 ↳ linter/@azure-tools/typespec-azure-core/rpc-operation-request-body 🟢 0.7ms 🟢 0.7ms +7.9%
 ↳ linter/@azure-tools/typespec-azure-core/spread-discriminated-model 🟢 0.4ms 🟢 0.5ms +5.5%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-names 🟢 7.3ms 🟢 7.9ms +7.7%
 ↳ linter/@azure-tools/typespec-azure-core/use-standard-operations 🟢 0.2ms 🟢 0.3ms +2.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-child-resources 🔴 20.2ms 🔴 22.2ms +9.8% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-agent-base-type-lifecycle-operations 🟢 0.2ms 🟢 0.3ms +12.7%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-common-types-version 🟡 11.6ms 🟡 12.4ms +6.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-no-key 🟢 0.2ms 🟢 0.2ms +10.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-custom-resource-usage-discourage 🟢 0.1ms 🟢 0.1ms +6.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-delete-operation-response-codes 🟢 5.4ms 🟢 4.5ms -15.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-path-casing-conflicts 🟡 16.5ms 🟡 17.2ms +4.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-no-record 🟢 0.6ms 🟢 0.6ms +3.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-post-operation-response-codes 🟢 1.4ms 🟢 1.4ms +0.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-put-operation-response-codes 🟢 0.2ms 🟢 0.2ms -3.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-action-no-segment 🟢 0.4ms 🟢 0.4ms +3.0%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-duplicate-property 🟢 0.4ms 🟢 0.4ms +6.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-interface-requires-decorator 🟢 0.1ms 🟢 0.1ms +8.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-action-verb 🟢 0.2ms 🟢 0.2ms +4.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-envelope-property 🟢 0.3ms 🟢 0.3ms +6.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-invalid-version-format 🟢 0.2ms 🟢 0.2ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-key-invalid-chars 🟢 0.5ms 🟢 0.5ms +11.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-name-pattern 🟢 0.1ms 🟢 0.1ms +0.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation 🟢 0.5ms 🟢 0.5ms +5.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-operation-response 🟢 8.5ms 🟢 9.1ms +6.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-patch 🟢 0.8ms 🟢 0.8ms +0.6%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-path-segment-invalid-chars 🟢 0.4ms 🟢 0.4ms +4.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/arm-resource-provisioning-state 🟢 0.4ms 🟢 0.4ms +3.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/beyond-nesting-levels 🟢 0.2ms 🟢 0.2ms +10.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/empty-updateable-properties 🟢 0.4ms 🟢 0.4ms +7.3%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/improper-subscription-list-operation 🟢 0.1ms 🟢 0.1ms +5.8%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/lro-location-header 🟡 18.8ms 🔴 20.7ms +10.2% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-operations-endpoint 🟢 0.1ms 🟢 0.1ms +7.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/missing-x-ms-identifiers 🟢 1.0ms 🟢 1.0ms +0.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-empty-model 🟢 0.2ms 🟢 0.3ms +4.9%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-override-props 🟢 0.3ms 🟢 0.3ms +0.5%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-resource-delete-operation 🟢 0.4ms 🟢 0.5ms +10.2%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/no-response-body 🔴 28.5ms 🔴 31.0ms +9.0% 🔴
 ↳ linter/@azure-tools/typespec-azure-resource-manager/patch-envelope 🟢 0.4ms 🟢 0.4ms +8.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/resource-name 🟢 0.4ms 🟢 0.4ms +4.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/secret-prop 🟢 5.2ms 🟢 5.4ms +2.4%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/unsupported-type 🟢 0.7ms 🟢 0.7ms +11.1%
 ↳ linter/@azure-tools/typespec-azure-resource-manager/version-progression 🟢 0.3ms 🟢 0.3ms -0.5%
 ↳ linter/@azure-tools/typespec-client-generator-core/property-name-conflict 🟢 2.2ms 🟢 2.3ms +4.7%
 ↳ linter/@azure-tools/typespec-client-generator-core/require-client-suffix 🟢 1.6ms 🟢 1.7ms +6.4%
emit 🔴 5.87s 🔴 6.16s +5.0%
 ↳ emit/@Azure-Tools 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@azure-tools/typespec-autorest 🟢 120.4ms 🟢 125.9ms +4.6%
 ↳ emit/@azure-tools/typespec-python 🔴 2.19s 🔴 2.30s +5.1% 🔴
 ↳ emit/@typespec 🟢 0.0ms 🟢 0.0ms +0.0%
 ↳ emit/@typespec/http-client-js 🔴 552.2ms 🔴 577.5ms +4.6%
 ↳ emit/@typespec/openapi3 🟢 103.4ms 🟢 109.6ms +6.0% 🔴
 ↳ emit/@typespec/openapi3/compute 🟢 89.7ms 🟢 95.2ms +6.1% 🔴
 ↳ emit/@typespec/openapi3/write 🟢 13.4ms 🟢 14.2ms +5.7%

Averaged across 3 specs (azure-arm-resource-manager, azure-core-dataplane, azure-full).
Threshold: changes > ±5% are highlighted.
🟢 Fast · 🟡 Moderate (stages >200ms, rules >10ms) · 🔴 Slow (stages >400ms, rules >20ms)

@v-jiaodi

v-jiaodi commented Jul 6, 2026

Copy link
Copy Markdown
Member

@copilot implementation body according to da95c89

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

Copilot AI commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot implementation body according to da95c89

Updated the implementation body to use early return pattern instead of ternary in commit fix(typespec-ts): use early return instead of ternary in body guard:

if (!result.body) {
  return;
}
return keyValueDeserializer(result.body);

Test snapshots updated accordingly.

@v-jiaodi

v-jiaodi commented Jul 6, 2026

Copy link
Copy Markdown
Member

@copilot fix ci format error.

…snapshot

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

Copilot AI commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix ci format error.

Fixed in commit fix(typespec-ts): fix prettier formatting in deserializeEmptyBody.md snapshot — removed the trailing newline from deserializeEmptyBody.md that caused the prettier format check to fail.

@v-jiaodi

v-jiaodi commented Jul 6, 2026

Copy link
Copy Markdown
Member

@copilot fix end-to-end Spector tests CI error.

…and model operation

Co-authored-by: v-jiaodi <80496810+v-jiaodi@users.noreply.github.com>

Copilot AI commented Jul 6, 2026

Copy link
Copy Markdown
Contributor Author

@copilot fix end-to-end Spector tests CI error.

Fixed in commit fix(typespec-ts): update routes index.d.ts with new ExpandParameters and model operation. The CI failure was due to a new model operation (and its ExpandParameters type) added to the routes spec in @typespec/http-specs that came in via the merge from main — the committed index.d.ts was missing those 9 lines.

@v-jiaodi v-jiaodi added this pull request to the merge queue Jul 6, 2026
Merged via the queue into main with commit d56eaff Jul 6, 2026
26 checks passed
@v-jiaodi v-jiaodi deleted the copilot/update-response-code-204-status branch July 6, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:typescript Issues for @azure-tools/typespec-ts emitter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[emitter] How to generate response code for returning body or 204 empty body status code

3 participants