Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types: Fix type implementation for CompatibleString #27180

Merged
merged 1 commit into from
May 22, 2024
Merged

Types: Fix type implementation for CompatibleString #27180

merged 1 commit into from
May 22, 2024

Conversation

sni-J
Copy link
Contributor

@sni-J sni-J commented May 17, 2024

Fix issue from #27088 (which closed #23232)

What I did

Thanks to @valentinpalkovic, previous issue(#23232) is resolved in latest release 8.1.1,
but sadly issue didn't resolved.

Type 'string' is not assignable to type 'FrameworkName'

/**
* Given a generic string type, returns that type but ensures that a string in general is compatible with it.
* We use this construct to ensure that IDEs can provide better autocompletion for string types.
* This is, for example, needed for main config fields, where we want to ensure that the user can provide
* a custom string, but also a string that is compatible with the type.
* @example
* type Framework = CompatibleString<'@storybook/nextjs'>
* const framework: Framework = '@storybook/nextjs'; // valid and will be autocompleted
* const framework: Framework = path.dirname(require.resolve(path.join("@storybook/nextjs", "package.json"))) // valid
*/
export type CompatibleString<T extends string> = T | (string & Record<string, never>);

Looks like T | (string & Record<string, never>) instead of T | (string & {}) does not correctly do the trick, so checked code below on TS Playground with TS 5.4.5.

const emptyObjectTest: "bar" | (string & {}) = "foo";

// Type '"foo"' is not assignable to type '(string & Record<string, never>) | "bar"'.
const recordNeverTest: "bar" | (string & Record<string, never>) = "foo";

// ---

type EmptyObjectTest = "foo" extends ("bar" | (string & {})) ? "true" : "false"; // "true"
type RecordNeverTest = "foo" extends ("bar" | (string & Record<string, never>)) ? "true" : "false"; // "false"

Since current implementation cannot solve problem, I updated CompatibleString to T | (string & {}).

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. Run a sandbox yarn start
  2. Define the framework field or framework.name field as a random string. This should be valid.
  3. Make sure that @storybook/react-vite (or specific framework that sandbox is based on) gets autocompleted or suggested by the IDE

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/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>

Copy link

nx-cloud bot commented May 17, 2024

☁️ Nx Cloud Report

CI is running/has finished running commands for commit 739cf3b. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.

📂 See all runs for this CI Pipeline Execution


✅ Successfully ran 1 target

Sent with 💌 from NxCloud.

Copy link
Contributor

@valentinpalkovic valentinpalkovic left a comment

Choose a reason for hiding this comment

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

LGTM! Thank you for your contribution. Indeed, my first attempt was to use string & {}, but ESLint wasn't really happy about it. Strangely, I could satisfy TypeScript with string & Record<string, never>. Potentially, not all TypeScript versions will understand this.

@valentinpalkovic valentinpalkovic merged commit 0616c33 into storybookjs:next May 22, 2024
54 of 56 checks passed
@github-actions github-actions bot mentioned this pull request May 22, 2024
25 tasks
@sni-J sni-J deleted the 23232-27088-compatible-string-implementation-fix branch May 28, 2024 14:54
@sni-J
Copy link
Contributor Author

sni-J commented Jul 15, 2024

@valentinpalkovic
Replying on closed PR might not be appropriate but just found something while digging on another issue from my own project so leaving it here for sharing.

Not sure exactly how 'ESLint wasn't really happy' in your case, but seems likely be related to @typescript-eslint/ban-types I think...?

According to typescript-eslint/typescript-eslint#6486, they are suggesting to use NonNullable<unknown> instead of {} for any non-nullish value, which is exactly what this fix wants (intersect string with any non-nullish value).

However, this works only on TS >= 4.8, tested on 4.7.4 in TS Playground and fail to autocomplete, since this change made NonNullable<unknown> equals to {}.

Enforcing minimum TS version might not be ideal to storybook or need extra discussion so I won't create PR on NonNullable<unknown> replacement, but hope this can help you and your team a little bit.

@valentinpalkovic
Copy link
Contributor

Thanks for letting us know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug]: React+Vite+TS PnP breaks type in .storybook/main.ts > config.framework.name
2 participants