Skip to content

fix: replace @ts-ignore with Metro-specific type definitions#832

Merged
dannyhw merged 3 commits into
storybookjs:nextfrom
YevheniiKotyrlo:fix/remove-ts-ignore-require-context
Feb 20, 2026
Merged

fix: replace @ts-ignore with Metro-specific type definitions#832
dannyhw merged 3 commits into
storybookjs:nextfrom
YevheniiKotyrlo:fix/remove-ts-ignore-require-context

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Jan 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Removes @ts-ignore comment from generated storybook.requires.ts by providing proper Metro type definitions.

Previous approach (rejected): Added @types/webpack-env as dependency.

New approach (per maintainer feedback): Custom Metro type definitions following the same pattern used by Expo.

Background Research

Metro's require.context API intentionally matches webpack's API by design (Metro PR #822), but the runtime implementations differ. Rather than using webpack types, this PR provides Metro-specific types.

How Expo handles this:

  • Expo manually maintains Metro types at packages/expo/types/metro-require.d.ts
  • Created by Mark Lawlor in PR #24255 (Sept 2023)
  • Uses __MetroModuleApi namespace to avoid conflicts with other type definitions
  • Based on webpack-env types but customized for Metro's implementation

Why not auto-convert from Flow?

  • Metro is written in Flow, not TypeScript
  • Automated Flow-to-TypeScript converters fail on Metro's complex type definitions
  • No one in the ecosystem (Expo, React Native) auto-converts these types
  • Manual types with clear source references is the standard approach

Changes

  1. metro-env.d.ts - New file with Metro type definitions

    • __MetroModuleApi.RequireContext - require.context() return type
    • __MetroModuleApi.RequireFunction - require.context() method signature
    • __MetroModuleApi.Hot - module.hot HMR API
    • Extends NodeJS.Require and NodeModule interfaces
  2. package.json

    • Removed @types/webpack-env dependency
    • Added "./metro-env": "./metro-env.d.ts" export
  3. scripts/generate.js

    • Adds /// <reference types="@storybook/react-native/metro-env" /> to generated TypeScript files

References

Test Plan

  • yarn test:generate passes
  • Generated files include proper type reference
  • No @ts-ignore needed in generated code

@dannyhw

dannyhw commented Jan 11, 2026

Copy link
Copy Markdown
Member

Hey thanks for this PR, however I wouldn't want to add this dependency personally.

I understand the intention behind this pr, however I don't think this is the right fix since the metro implementation doesn't match the webpack one and we shouldn't rely on any dependency to webpack in my opinion.

If anything we should copy the type definitions from expo here
https://github.com/expo/expo/blob/main/packages/expo/types/metro-require.d.ts

However its also low priority in my opinion since this ts-ignore exists in a generated file that can be ignored in eslint

@YevheniiKotyrlo YevheniiKotyrlo changed the title fix: remove @ts-ignore by adding @types/webpack-env dependency fix: replace @ts-ignore with Metro-specific type definitions Jan 12, 2026
@YevheniiKotyrlo YevheniiKotyrlo force-pushed the fix/remove-ts-ignore-require-context branch from bcf7930 to 32921da Compare February 6, 2026 16:47
@YevheniiKotyrlo YevheniiKotyrlo force-pushed the fix/remove-ts-ignore-require-context branch from 32921da to 08a609c Compare February 17, 2026 17:11
@changeset-bot

changeset-bot Bot commented Feb 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 54992d2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@storybook/react-native Patch
@storybook/react-native-ui Patch
@storybook/react-native-ui-lite Patch
@storybook/react-native-ui-common Patch
@storybook/react-native-theming Patch
@storybook/addon-ondevice-actions Patch
@storybook/addon-ondevice-backgrounds Patch
@storybook/addon-ondevice-controls Patch
@storybook/addon-ondevice-notes Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Replace @types/webpack-env dependency with custom Metro type definitions,
following the same approach used by Expo.

Metro's require.context API intentionally matches webpack's API by design,
but using webpack types caused concerns about API differences.

This change:
- Adds metro-env.d.ts with Metro-specific types in __MetroModuleApi namespace
- Exports types via @storybook/react-native/metro-env
- Auto-injects reference directive in generated storybook.requires.ts files
- Removes both @ts-ignore comments from generated code

References:
- Expo's approach: https://github.com/expo/expo/blob/main/packages/expo/types/metro-require.d.ts
- Metro require.context PR: react/metro#822
- Metro HMR Flow types: https://github.com/facebook/metro/blob/main/packages/metro-runtime/src/polyfills/require.js.flow
@YevheniiKotyrlo YevheniiKotyrlo force-pushed the fix/remove-ts-ignore-require-context branch from 08a609c to f6840bb Compare February 17, 2026 17:25
@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

Hey @dannyhw, I've rebased this onto the latest next and addressed your feedback from the previous iteration:

  • Removed @types/webpack-env entirely
  • Added custom metro-env.d.ts with Metro-specific types in the __MetroModuleApi namespace, following the same approach Expo uses in their metro-require.d.ts
  • The generated storybook.requires.ts now uses /// <reference types="@storybook/react-native/metro-env" /> instead of @ts-ignore
  • Added a changeset

No new dependencies added. Would you be able to take another look when you get a chance?

@dannyhw

dannyhw commented Feb 17, 2026

Copy link
Copy Markdown
Member

Hey, thanks for that. I'm just wondering if you could clarify whats the pain point that this solves? Does this tsignore break something for you currently?

Just so i can understand better where this is coming from

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

The main pain point is that the generated storybook.requires.ts can't participate in the project's type-checking and linting pipeline.

Our project runs strict: true TypeScript with strictTypeChecked ESLint rules. The @ts-ignore comments in the generated file mean we have to explicitly exclude it from our ESLint config:

// eslint.config.ts — ignores
'**/storybook/storybook.requires.ts',

This creates a blind spot — if the generated code has an actual type error beyond the missing require.context/module.hot types, it's invisible to our CI. The @ts-ignore suppresses all errors on the line, not just the missing type.

With proper Metro types via metro-env.d.ts, the generated file can be linted and type-checked like everything else — no exclusions needed.

@dannyhw

dannyhw commented Feb 17, 2026

Copy link
Copy Markdown
Member

you actually should ignore the requires file from eslint, its a generated file and its not possible to satisfy every project's lint configuration.

I think its valid to aim to remove ts ignore but i don't think it will fix linting problems.

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

That's a good point — and you're right that ignoring it from ESLint is the practical approach. The challenge though is that storybook.requires.ts gets regenerated by generate() on every expo start via the withStorybook() Metro wrapper. So even if a user removes the @ts-ignore manually, the next dev server start overwrites the file and brings them back.

The only way to prevent that currently is to patch @storybook/react-native's scripts/generate.js — which is what we've been doing on our end. This PR removes the need for that kind of workaround by having generate() emit a /// <reference types> directive instead of @ts-ignore, backed by proper Metro types in metro-env.d.ts.

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

Let me know if you have any concerns about the approach or if there's anything else you'd like me to test or adjust before this can be merged. Happy to make changes if needed!

@dannyhw

dannyhw commented Feb 17, 2026

Copy link
Copy Markdown
Member

Ok thanks, I will take a proper look tomorrow. Sorry that its been stuck for a while.

@dannyhw

dannyhw commented Feb 20, 2026

Copy link
Copy Markdown
Member

Doesn't appear to work for module.hot

> expo-example@10.2.2-alpha.5 check /Users/danielwilliams/Developer/storybook/react-native-storybook/examples/expo-example
> tsc --noEmit

.rnstorybook/storybook.requires.ts:66:9 - error TS2339: Property 'hot' does not exist on type 'Module'.

66 module?.hot?.accept?.();
           ~~~


Found 1 error in .rnstorybook/storybook.requires.ts:66

applied a small fix

@dannyhw dannyhw merged commit d2f2d99 into storybookjs:next Feb 20, 2026
1 check passed
@dannyhw

dannyhw commented Feb 20, 2026

Copy link
Copy Markdown
Member

available to try on 10.3.0-canary-20260220230836

@dannyhw

dannyhw commented Feb 20, 2026

Copy link
Copy Markdown
Member

thanks for your work and patience @YevheniiKotyrlo

@YevheniiKotyrlo

Copy link
Copy Markdown
Contributor Author

thanks for your work and patience @YevheniiKotyrlo

Thank you for your hard work!

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