Skip to content

CSF: Support satisfies x as y syntax#32169

Merged
shilman merged 5 commits into
storybookjs:nextfrom
diagramatics:satisfies-as
Sep 5, 2025
Merged

CSF: Support satisfies x as y syntax#32169
shilman merged 5 commits into
storybookjs:nextfrom
diagramatics:satisfies-as

Conversation

@diagramatics
Copy link
Copy Markdown
Contributor

@diagramatics diagramatics commented Aug 1, 2025

What I did

We use satisfies Meta as Meta to enable isolatedDeclarations in our TypeScript configs. Unfortunately satisfies is a "weak" operator that only exists to imply some additional typechecking. It does not change the type of the expression or imply some true relationship with the annotation. So TS cannot use the annotation for the module signature.

csf-tools doesn't support this syntax, so this PR fixes it by checking for satisfies..as.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

  1. Start from next branch and edit code/renderers/react/template/stories/decorators.stories.tsx to add satisfies Meta<typeof Component> as Meta<typeof Component> in the default export.
  2. Run yarn start on root to spin up the test sandbox
  3. This will fail with 🚨 Unable to index ./src/stories/renderers/react/decorators.stories.tsx: NoMetaError: CSF: default export must be an object
  4. Apply this PR, re-run yarn start. It should pass and parse the CSF correctly.

Diff to edit the file below.

diff --git a/code/renderers/react/template/stories/decorators.stories.tsx b/code/renderers/react/template/stories/decorators.stories.tsx
index e1014e7ee91..c273a2f1a61 100644
--- a/code/renderers/react/template/stories/decorators.stories.tsx
+++ b/code/renderers/react/template/stories/decorators.stories.tsx
@@ -18,7 +18,7 @@ export default {
       </>
     ),
   ],
-} as Meta<typeof Component>;
+} satisfies Meta<typeof Component> as Meta<typeof Component>;
 
 export const All: StoryObj<typeof Component> = {
   decorators: [

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Greptile Summary

This PR adds support for parsing the TypeScript satisfies Meta as Meta syntax in Storybook's CSF (Component Story Format) tools. The change addresses a specific need for TypeScript's isolatedDeclarations feature, which requires stronger type annotations for module signatures.

The problem being solved is that the satisfies operator alone is considered "weak" by TypeScript - it provides compile-time type checking but doesn't contribute to the module's type signature generation. To enable isolatedDeclarations, developers need to use satisfies Meta as Meta, combining both type checking (satisfies) and explicit type assertion (as).

The implementation extends the existing TypeScript AST parsing logic in CsfFile.ts to handle the nested structure TSAsExpression(TSSatisfiesExpression(ObjectExpression)). The parser now recognizes this pattern in three key locations:

  1. Default export declarations - handling export default { ... } satisfies Meta as Meta
  2. Named export variable declarations - handling const meta = { ... } satisfies Meta as Meta
  3. Export specifiers - handling various export patterns with the new syntax

The changes are minimal and focused, adding conditional branches to detect and unwrap the nested AST structure to extract the underlying object expression. Comprehensive test coverage has been added to verify the parser correctly handles all variations of the new syntax alongside existing patterns.

This enhancement ensures Storybook's CSF tools remain compatible with modern TypeScript features while maintaining backward compatibility with existing syntax patterns.

Confidence score: 4/5

  • This PR is generally safe to merge with well-structured changes and comprehensive test coverage
  • The implementation correctly handles the nested TypeScript AST structure and maintains backward compatibility
  • The changes are focused and minimal, reducing risk of unintended side effects

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Bot Settings | Greptile

Comment thread code/core/src/csf-tools/CsfFile.ts Outdated
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Aug 1, 2025

View your CI Pipeline Execution ↗ for commit 416cb00

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 44s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-04 23:52:33 UTC

@yannbf yannbf self-assigned this Aug 4, 2025
@yannbf yannbf changed the title Support satisfies..as on csf-tools parsing Csf: Support satisfies x as y syntax Aug 4, 2025
@storybook-app-bot
Copy link
Copy Markdown

storybook-app-bot Bot commented Aug 4, 2025

Package Benchmarks

Commit: 416cb00, ran on 4 September 2025 at 23:42:29 UTC

No significant changes detected, all good. 👏

@github-actions github-actions Bot added the Stale label Aug 17, 2025
@diagramatics
Copy link
Copy Markdown
Contributor Author

Commenting in case this goes stale. @yannbf all good here?

@vanessayuenn vanessayuenn assigned shilman and unassigned yannbf Sep 1, 2025
@shilman
Copy link
Copy Markdown
Member

shilman commented Sep 1, 2025

Hey @diagramatics, thanks for your PR!

I don't like complexifying CSF support in this way, but I understand the desire to make the use of the latest TS features. Also the CSF code that you're using is a bit of an eyesore!!! I highly recommend taking a look at CSF Factories, released as experimental in 9.0 and going "preview" in 10.0 next month.

If that works for you and eliminates the need for this PR, I'll close this. But if it's too fresh or you have some other constraints, I can begrudgingly merge this to get you unblocked. Thanks for your patience!!

@diagramatics
Copy link
Copy Markdown
Contributor Author

Thanks @shilman! Yeah CSF factories looks like it's going to be too fresh for us, especially coming out of migrating some really dynamic storiesOf usage just recently. We have this change as a pnpm patch in our large codebase already so merging this will make our upgrade from v8 to v9 (or v10 if we're slower than you folks) easier 😅

@shilman shilman added maintenance User-facing maintenance tasks and removed feature request labels Sep 4, 2025
@shilman shilman changed the title Csf: Support satisfies x as y syntax CSF: Support satisfies x as y syntax Sep 4, 2025
@shilman shilman added the patch:yes Bugfix & documentation PR that need to be picked to main branch label Sep 4, 2025
@shilman
Copy link
Copy Markdown
Member

shilman commented Sep 4, 2025

@diagramatics Understood. Merging & will patch it back to 9.x to help unblock your efforts!!

@shilman shilman merged commit 9eca72f into storybookjs:next Sep 5, 2025
51 checks passed
shilman added a commit that referenced this pull request Sep 6, 2025
CSF: Support `satisfies x as y` syntax
(cherry picked from commit 9eca72f)
@github-actions github-actions Bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Sep 6, 2025
@github-actions github-actions Bot mentioned this pull request Sep 16, 2025
23 tasks
@ndelangen ndelangen removed the patch:yes Bugfix & documentation PR that need to be picked to main branch label Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal csf maintenance User-facing maintenance tasks patch:done Patch/release PRs already cherry-picked to main/release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants