Skip to content

Type mismatch with Expo's Metro config with custom Babel transformer #5176

@ybentz

Description

@ybentz

What React Native libraries do you use?

Hermes, RN New Architecture, Expo Application Services (EAS), Expo (mobile only), Expo Router

Are you using sentry.io or on-premise?

sentry.io (SaS)

@sentry/react-native SDK Version

6.20.0

How does your development environment look like?

OS: macOS 15.6.1
CPU: (10) arm64 Apple M1 Pro
Node: 22.18.0
Typescript: 5.9.2
Yarn: 1.22.22
CocoaPods: 1.15.2
Expo SDK: 54.0.8
react-native: 0.81.4
react: 19.1.0
hermesEnabled: true
newArchEnabled: true

Sentry.init()

const routingInstrumentation = Sentry.reactNavigationIntegration()
Sentry.init({
  dsn: sentryDsn,
  debug: false,
  integrations: [
    Sentry.reactNativeTracingIntegration({
      routingInstrumentation,
    }),
    extraErrorDataIntegration({ depth: 10 }),
  ],
})

Steps to Reproduce

My Expo app is using a custom Babel transformer to enable both the annotateReactComponents feature from Sentry along with setting up react-native-svg-transformer. I originally opened the issue that resulted in Sentry exposing the ability to provide a custom transformer which was super helpful!

I'm now trying to upgrade my app to Expo 54 (from 53) which also upgrades @sentry/react-native from 6.14.0 to 6.20.0.

I'm not yet sure what changed in either of the libraries or both, but my existing metro config implementation which is essentially identical to the Sentry docs breaks Typescript in 2 places.

Here's my exact implementation:

import { getDefaultConfig } from "@expo/metro-config"
import { getSentryExpoConfig } from "@sentry/react-native/metro"

module.exports = (() => {
  const config = getSentryExpoConfig(__dirname, {
    annotateReactComponents: true,
    // https://github.com/getsentry/sentry-react-native/issues/4459#issuecomment-2604663029
    getDefaultConfig: (projectRoot, options) => {
      const config = getDefaultConfig(projectRoot, options)
      const { transformer, resolver } = config

      const newConfig = { ...config }
      newConfig.transformer = {
        ...transformer,
        babelTransformerPath: require.resolve("react-native-svg-transformer/expo"),
      }
      newConfig.resolver = {
        ...resolver,
        assetExts: resolver?.assetExts?.filter((ext) => ext !== "svg"),
        sourceExts: [...(resolver?.sourceExts ?? []), "svg"],
      }
      return newConfig
    },
  })

  return config
})()

Here are the

  1. Looks like there's a mismatch between the expected and actual return type for getDefaultConfig that's being passed in the options object to getSentryExpoConfig (this line getDefaultConfig: (projectRoot, options) => {). Here's the TS error:
Type '(projectRoot: string, options: (DefaultConfigOptions & SentryExpoConfigOptions & SentryMetroConfigOptions) | undefined) => { ...; }' is not assignable to type '(projectRoot: string, options?: (DefaultConfigOptions & SentryExpoConfigOptions & SentryMetroConfigOptions) | undefined) => InputConfigT'.
  Call signature return types '{ cacheStores?: readonly CacheStore<TransformResult<MixedOutput>>[] | (readonly CacheStore<TransformResult<MixedOutput>>[] & (($$PARAM_0$$: typeof import(".../node_modules/@expo/metro/metro-cache/index")) => readonly CacheStore<...>[])) | undefined; ... 17 more ...; watcher?: Readonly...' and 'InputConfigT' are incompatible.
    The types of 'cacheStores' are incompatible between these types.
      Type 'readonly CacheStore<TransformResult<MixedOutput>>[] | (readonly CacheStore<TransformResult<MixedOutput>>[] & (($$PARAM_0$$: typeof import(".../node_modules/@expo/metro/metro-cache/index")) => readonly CacheStore<...>[])) | undefined' is not assignable to type 'readonly CacheStore<TransformResult<MixedOutput>>[] | ((metroCache: MetroCache) => readonly CacheStore<TransformResult<MixedOutput>>[]) | undefined'.
        Type 'readonly CacheStore<TransformResult<MixedOutput>>[]' is not assignable to type 'readonly CacheStore<TransformResult<MixedOutput>>[] | ((metroCache: MetroCache) => readonly CacheStore<TransformResult<MixedOutput>>[]) | undefined'.
          Type 'readonly import(".../node_modules/@expo/metro/metro-cache/types.flow").CacheStore<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").TransformResult<import(".../node_modules/@expo/metro/metro/DeltaBundle...' is not assignable to type 'readonly import(".../node_modules/metro-cache/src/types").CacheStore<import(".../node_modules/metro/src/DeltaBundler/types").TransformResult<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>>[]'.
            Type 'import(".../node_modules/@expo/metro/metro-cache/types.flow").CacheStore<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").TransformResult<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.f...' is not assignable to type 'import(".../node_modules/metro-cache/src/types").CacheStore<import(".../node_modules/metro/src/DeltaBundler/types").TransformResult<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>>'.
              The types returned by 'get(...)' are incompatible between these types.
                Type 'TransformResult<MixedOutput> | Promise<TransformResult<MixedOutput> | null | undefined> | null | undefined' is not assignable to type 'TransformResult<MixedOutput> | Promise<undefined> | Promise<TransformResult<MixedOutput>> | undefined'.
                  Type 'null' is not assignable to type 'TransformResult<MixedOutput> | Promise<undefined> | Promise<TransformResult<MixedOutput>> | undefined'.
  1. The options object that we pass to the getDefaultConfig function imported from @expo/metro-config (this line const config = getDefaultConfig(projectRoot, options) also has a type mismatch between expected and provided. Here's the full TS error:
Argument of type '(DefaultConfigOptions & SentryExpoConfigOptions & SentryMetroConfigOptions) | undefined' is not assignable to parameter of type 'DefaultConfigOptions | undefined'.
  Type 'DefaultConfigOptions & SentryExpoConfigOptions & SentryMetroConfigOptions' is not assignable to type 'DefaultConfigOptions | undefined'.
    Type 'DefaultConfigOptions & SentryExpoConfigOptions & SentryMetroConfigOptions' is not assignable to type 'DefaultConfigOptions'.
      Types of property 'unstable_beforeAssetSerializationPlugins' are incompatible.
        Type '((serializationInput: { graph: import(".../node_modules/metro/src/DeltaBundler/types").ReadOnlyGraph<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>; premodules: import(".../node_modules/metro/src/Del...' is not assignable to type '((serializationInput: { graph: import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").ReadOnlyGraph<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").MixedOutput>; premodules: import(".../...'.
          Type '((serializationInput: { graph: import(".../node_modules/metro/src/DeltaBundler/types").ReadOnlyGraph<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>; premodules: import(".../node_modules/metro/src/Del...' is not assignable to type '((serializationInput: { graph: import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").ReadOnlyGraph<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").MixedOutput>; premodules: import(".../...'.
            Type '(serializationInput: { graph: import(".../node_modules/metro/src/DeltaBundler/types").ReadOnlyGraph<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>; premodules: import(".../node_modules/metro/src/Delt...' is not assignable to type '(serializationInput: { graph: import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").ReadOnlyGraph<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").MixedOutput>; premodules: import(".../n...'.
              Types of parameters 'serializationInput' and 'serializationInput' are incompatible.
                Type '{ graph: import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").ReadOnlyGraph<import(".../node_modules/@expo/metro/metro/DeltaBundler/types.flow").MixedOutput>; premodules: import(".../node_modules/@expo/met...' is not assignable to type '{ graph: import(".../node_modules/metro/src/DeltaBundler/types").ReadOnlyGraph<import(".../node_modules/metro/src/DeltaBundler/types").MixedOutput>; premodules: import(".../node_modules/metro/src/DeltaBundler/types").Modu...'.
                  The types of 'graph.transformOptions.platform' are incompatible between these types.
                    Type 'string | null | undefined' is not assignable to type 'string | undefined'.
                      Type 'null' is not assignable to type 'string | undefined'.

Expected Result

There should be no TS errors in the metro.config.ts file.

Actual Result

The errors described above.

Metadata

Metadata

Assignees

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions