Skip to content

fix(s3): make Bucket assignable to IBucket under exactOptionalPropertyTypes - #38104

Open
laazyj wants to merge 2 commits into
aws:mainfrom
laazyj:s3-exactoptional
Open

fix(s3): make Bucket assignable to IBucket under exactOptionalPropertyTypes#38104
laazyj wants to merge 2 commits into
aws:mainfrom
laazyj:s3-exactoptional

Conversation

@laazyj

@laazyj laazyj commented Jun 6, 2026

Copy link
Copy Markdown

Issue # (if applicable)

Refs #37996 (reported by @mingkunm on the issue).

Reason for this change

IBucket.isWebsite is declared optional (?: boolean), but Bucket exposed it through a getter typed boolean | undefined (delegating to BucketReflection). Under TypeScript's exactOptionalPropertyTypes, a member typed T | undefined is not assignable to an optional ?: T, so consumers who enable that flag hit a TS2375 error when passing a Bucket where an IBucket is expected (e.g. BucketProps.serverAccessLogsBucket), and type-checking aws-cdk-lib fails for them outright:

const b: IBucket = new Bucket(stack, 'B'); // TS2375 under exactOptionalPropertyTypes

aws-cdk-lib does not build with the flag, so the break is invisible to the library's own compile. Notably, Bucket satisfies IBucket through BucketBase (which declares abstract readonly isWebsite?: boolean), so there is no TS2420 at the class — the break only surfaces as a call-site assignment failure. This is one package in the sweep tracked by #37996.

Description of changes

Convert isWebsite (on Bucket and the internal fromCfnBucket subclass) from a getter to a public readonly isWebsite?: boolean field, set in the constructor from this.reflection.isWebsite once the underlying CfnBucket (with its website configuration) exists.

  • Narrowing the getter to : boolean is not an option — jsii rejects a required getter overriding the optional abstract member (JSII5009). The readonly field is the shape that satisfies both jsii and the flag.
  • The property stays optional and immutable in the jsii assembly, so this is not an API change; yarn compat passes with no new entry.
  • Website hosting on an L2 Bucket is configured by props at construction (there is no post-construction L2 API to enable it), so capturing the value at construction is behaviour-preserving for supported usage. The existing isWebsite unit tests are unchanged and pass.

New: an auto-enumerating regression guard

This PR introduces a shared helper in @aws-cdk/cdk-build-tools, exactOptionalAssignabilityDiagnosticsForPackage(testDir), which enumerates every exported, non-abstract class in a package and type-checks its assignability to each interface it implements (its own and inherited) under the flag. Enumerating — rather than hand-listing classes — keeps the guard complete by construction: a newly-added offending class (or a new optional getter on an existing one) is caught automatically. The aws-s3 guard test is a one-liner over this helper, and subsequent sweep packages can adopt it the same way.

Description of how you validated your changes

  • The package-local guard (aws-s3/test/exact-optional-property-types.test.ts) passes; verified it goes red with the precise diagnostic Bucket -> IBucket: TS2375 [isWebsite] if the fix is reverted.
  • The existing isWebsite behaviour tests (default false, true for each website configuration) are unchanged and pass; full aws-s3 suite green.
  • yarn compat passes (no assembly change); lint clean.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

…yTypes

`IBucket.isWebsite` is declared optional (`?: boolean`), but `Bucket` exposed it
through a getter typed `boolean | undefined` (delegating to `BucketReflection`).
Under TypeScript's `exactOptionalPropertyTypes`, a member typed `T | undefined`
is not assignable to an optional `?: T`, so consumers who enable the flag get a
TS2375 error when passing a `Bucket` where an `IBucket` is expected (e.g.
`BucketProps.serverAccessLogsBucket`), and type-checking `aws-cdk-lib` fails for
them outright. The library does not build with the flag, so the break is
invisible to its own compile. Reported by a user on aws#37996.

`Bucket` satisfies `IBucket` through `BucketBase`, which declares
`abstract readonly isWebsite?: boolean`, so there is no TS2420 at the class — the
break only surfaces as a call-site assignment failure, which a class-level scan
misses.

Convert `isWebsite` (on `Bucket` and the internal `fromCfnBucket` subclass) from
a getter to a `public readonly isWebsite?: boolean` field, set in the constructor
from `this.reflection.isWebsite` once the underlying `CfnBucket` (with its website
configuration) exists. Narrowing the getter to `: boolean` is not an option — jsii
rejects a required getter overriding the optional abstract member (JSII5009) — so
the field is the shape that satisfies both jsii and the flag. The property stays
optional and immutable in the jsii assembly, so this is not an API change and
`yarn compat` passes. Website hosting is configured by props at construction, so
capturing the value there is behaviour-preserving.

Add a package-local regression guard. This PR also introduces a shared,
auto-enumerating helper in `@aws-cdk/cdk-build-tools`,
`exactOptionalAssignabilityDiagnosticsForPackage(testDir)`, which enumerates every
exported, non-abstract class in a package and type-checks its assignability to
each interface it implements (own and inherited) under the flag — so the guard is
complete by construction and catches a newly-added offending class automatically,
rather than relying on a hand-maintained list.

Refs aws#37996
@github-actions github-actions Bot added p2 beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK labels Jun 6, 2026
@laazyj

laazyj commented Jun 6, 2026

Copy link
Copy Markdown
Author

Exemption Request: This is a type-only change — it converts an existing read-only getter (Bucket.isWebsite) to an equivalent readonly field so the class is assignable to its interface under exactOptionalPropertyTypes. There is no runtime behaviour change and no change to synthesized output or the jsii assembly (the property stays optional and immutable; yarn compat passes with no new entry), so an integration test would add nothing. The change is covered by the existing isWebsite unit tests plus a package-local type-assignability guard. Requesting the pr-linter/exempt-integ-test label.

@aws-cdk-automation aws-cdk-automation added the pr-linter/exemption-requested The contributor has requested an exemption to the PR Linter feedback. label Jun 6, 2026

@aws-cdk-automation aws-cdk-automation left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pull request linter fails with the following errors:

❌ Fixes must contain a change to an integration test file and the resulting snapshot.

If you believe this pull request should receive an exemption, please comment and provide a justification. A comment requesting an exemption should contain the text Exemption Request. Additionally, if clarification is needed, add Clarification Request to a comment.

✅ A exemption request has been requested. Please wait for a maintainer's review.

@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Jul 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

beginning-contributor [Pilot] contributed between 0-2 PRs to the CDK p2 pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. pr-linter/exemption-requested The contributor has requested an exemption to the PR Linter feedback.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants