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

Fix: TypeScript Type Portability Issues #4467

Open
wants to merge 85 commits into
base: master
Choose a base branch
from

Conversation

aryaemami59
Copy link
Contributor

@aryaemami59 aryaemami59 commented Jun 19, 2024

Overview

The type portability issues in this repository are primarily caused by three specific TypeScript errors:

  1. TS4023: Exported variable 'useAppDispatch' has or is using name 'TimeResponse' from external module "/home/runner/work/redux-toolkit/redux-toolkit/examples/publish-ci/vite/src/app/services/times" but cannot be named.

    • Solution: This one can actually be resolved quite often by converting the problematic type from an interface to a type alias. Other times we might have to export the problematic type.
  2. TS2742: The inferred type of 'useGetQuotesQuery' cannot be named without a reference to '../../../node_modules/@reduxjs/toolkit/dist/query/react/buildHooks'. This is likely not portable. A type annotation is necessary.

    • Solution: Bundling the type definitions seems to have resolved this issue.
  3. TS2527: The inferred type of 'quotesApiSlice' references an inaccessible 'unique symbol' type. A type annotation is necessary.
    This one took a while for me to figure out, It turns out in order for a unique symbol type to be "accessible", the unique symbol has to be imported upon declaration, so we want something that looks like this:

    export declare const coreModuleName: unique symbol

    But dts-rollup-plugin gives us this instead:

    declare const coreModuleName: unique symbol
    export { coreModuleName }

    But TypeScript treats declare const coreModuleName: unique symbol and export { coreModuleName }; as 2 different unique symbols because each reference to coreModuleName is completely unique.

    • Solution: While somewhat hacky, I wrote a small script that takes all exported unique symbols and converts them from:

      declare const coreModuleName: unique symbol
      export { coreModuleName }

      To:

      export declare const coreModuleName: unique symbol

This PR:

  1. @examples-type-portability/bundler to test for "moduleResolution": "Bundler".
  2. @examples-type-portability/nodenext-cjs to test for "moduleResolution": "NodeNext" with TypeScript's CJS syntax and "type": "commonjs" in package.json.
  3. @examples-type-portability/nodenext-esm to test for "moduleResolution": "NodeNext" with ESM syntax and "type": "module" in package.json.

Things to keep in mind

  • Although I prefer using interfaces, it might be worthwhile to switch to type aliases going forward. interfaces are more prone to type portability issues compared to type aliases, which often dissolve into their constituents. I highly recommend using type aliases for all new types unless interfaces are necessary (e.g., for declaration merging).

  • I've noticed that using an interface as the return type of an external function often leads to type portability issues unless the interface itself is also exported.

- We also convert some of the problematic types from an `interface` to a `type` alias.
- The reason why `coreModuleName` and `reactHooksModuleName` are inaccessible is because in order for them to become public `unique symbols` we need to have `export declare const coreModuleName: unique symbol` as opposed to what `rollup-plugin-dts` does which is `declare const coreModuleName: unique symbol; export {
  coreModuleName }`.
- It seems like `tsup` can't handle `import type { Dispatch as ReduxDispatch }`, so we'll remove them.
- This was done to avoid name collision with `TypedActionCreator` in `src/mapBuilders.ts`
- This was done to prevent name collision with `GetState` type in `src/dynamicMiddleware/types.ts`
@aryaemami59 aryaemami59 force-pushed the fix-type-portability-issues branch 2 times, most recently from d94126d to 28d5a07 Compare July 9, 2024 19:14
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- This was done to resolve potential `TS4023` errors with TypeScript version 5.5.
- Move `@examples-type-portability/bundler` from `examples/type-portability` to `examples/type-portability/bundler`. This was done to make room for a `NodeNext` test.
- Added `@examples-type-portability/nodenext-cjs` to test type portability with `moduleResolution NodeNext` and TypeScript CJS syntax.
@aryaemami59
Copy link
Contributor Author

Alright this one should be good to go. Let me know if this needs anything.

@aryaemami59 aryaemami59 marked this pull request as ready for review July 9, 2024 22:04
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.

None yet

2 participants