Skip to content

fix: ensure SwipeDirection is imported as a value in ReanimatedSwipeable #3666

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

christianbach
Copy link

Summary
Fixes SwipeDirection being undefined at runtime in ReanimatedSwipeable when the package
is consumed from TypeScript source (e.g. in some Metro configs).

Details
SwipeDirection was imported from the local barrel (./index.ts), which re-exports it
as a type-only export. This removes the value in the compiled JS, causing it to be undefined
at runtime.

This PR imports SwipeDirection directly from ReanimatedSwipeableProps, which exports it
as a value.

See closed issue for details: #3665

Impact
No API changes. Only affects internal import, ensures enum value is present at runtime.

@christianbach
Copy link
Author

Perhaps @latekvo could take a look?

@christianbach
Copy link
Author

Forced push a new commit that fixes the lint error

@m-bert m-bert requested a review from latekvo August 12, 2025 07:03
Copy link
Member

@latekvo latekvo left a comment

Choose a reason for hiding this comment

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

Hey @christianbach, before I merge this I'd like to make sure: have you tested this fix on your project, and did it resolve your issues?

Your explanation for why this fix works does not seem to be true.
You're writing that ./index.ts [...] re-exports it as a type-only export , but that's not the case, SwipeDirection is exported as a value within the index.ts.

Regardless, if the fix you're proposing does fix this issue, I have nothing against merging it. Especially since there was another person reporting a similar problem.

Perhaps one last thing, is that if this issue occurs in ReanimatedSwipeable, then it'd be worth checking other components for a similar issue. Would you mind checking if you're encountering similar issues with the ReanimatedDrawerLayout? It also exports numerous Enums.

(c.c. @j-piasecki)

@christianbach
Copy link
Author

christianbach commented Aug 12, 2025

Your explanation for why this fix works does not seem to be true. You're writing that ./index.ts [...] re-exports it as a type-only export , but that's not the case, SwipeDirection is exported as a value within the index.ts.

You're absolutely right, my bad!

I did some more digging and this is really strange, if I change the import from:

import { SwipeableProps, SwipeableMethods, SwipeDirection } from '.';

to:

import { SwipeableProps, SwipeableMethods, SwipeDirection, } from './index';

Everything starts working as expected. It seems to me that metro is somehow striping SwipeDirection as a type or omitting the index.ts file entirely...

@latekvo
Copy link
Member

latekvo commented Aug 12, 2025

Hey, would you mind sharing your metro.config.js and tsconfig.json files? These could contain some useful insights.

@christianbach
Copy link
Author

Nothing out of the ordinary, we don't use the default tsconfig from react-native but it's similar.

metro.config.js

const path = require('path');
const fs = require('fs');
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');
const {withSentryConfig} = require('@sentry/react-native/metro');
const {
  wrapWithReanimatedMetroConfig,
} = require('react-native-reanimated/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const {assetExts, sourceExts} = defaultConfig.resolver;

/**
 * Metro configuration
 * https://facebook.github.io/metro/docs/configuration
 *
 * @type {import('@react-native/metro-config').MetroConfig}
 */

// Exclude devDependencies from watchFolders, include everything else
const excludesPackages = ['eslint-config', 'tsconfig', 'prettier-config'];
const watchFolders = fs
  .readdirSync(path.resolve(__dirname, '../../packages'))
  .filter(
    folder =>
      !excludesPackages.some(
        exclude => folder.includes(exclude) || folder.startsWith('.'),
      ),
  )
  .filter(Boolean)
  .map(folder => path.resolve(__dirname, `../../packages/${folder}`));

const config = {
  watchFolders: [
    path.resolve(__dirname, '../../node_modules'),
    ...watchFolders,
  ],

  transformer: {
    babelTransformerPath: require.resolve(
      'react-native-svg-transformer/react-native',
    ),
  },

  resolver: {
    assetExts: assetExts.filter(ext => ext !== 'svg'),
    sourceExts: [...sourceExts, 'svg', 'mjs', 'cjs'],
    // disable watchman for now, its just too slow and unstable
    useWatchman: false,
    // This needs to be here for react-strict-dom to work
    unstable_enablePackageExports: true,
    unstable_conditionNames: ['react-native', 'require', 'default'],
  },
};

const mergedConfig = mergeConfig(defaultConfig, config);

module.exports = withSentryConfig(wrapWithReanimatedMetroConfig(mergedConfig));

tsconfig.json

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "React Native",
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "types": ["react-native", "jest"],
    "lib": [
      "es2019",
      "es2020.bigint",
      "es2020.date",
      "es2020.number",
      "es2020.promise",
      "es2020.string",
      "es2020.symbol.wellknown",
      "es2021.promise",
      "es2021.string",
      "es2021.weakref",
      "es2022.array",
      "es2022.object",
      "es2022.string"
    ],
    "allowJs": true,
    "jsx": "react-native",
    "noEmit": true,
    "isolatedModules": true,
    "strict": true,
    "incremental": true,
    "moduleResolution": "bundler",
    "customConditions": ["react-native"],
    "moduleSuffixes": [".native", ""],
    "allowImportingTsExtensions": true,
    "allowArbitraryExtensions": true,
    "resolveJsonModule": true,
    "resolvePackageJsonImports": false,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": false,
    "strictFunctionTypes": true
  },
  "exclude": ["**/node_modules", "**/Pods", "**/ios", "**/android"]
}

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.

2 participants