Conversation
robhogan
added this pull request to stack #1997
September 29, 2026 14:48
….333 Summary: `flow-api-translator` 0.332.0 translates `declare module.exports` to TypeScript's `export =` (facebook/flow#9491). Until now `scripts/generateTypeScriptDefinitions.js` rejected any module whose Flow def used it, which is why all of `metro-runtime` bar `modules/types.js` was excluded, and why most of our hand-maintained `src/**/*.d.ts` overrides exist. With `flow-api-translator` on 0.333.0, this drops the `module.exports` rejection and the `metro-runtime` exclusion, and removes as many overrides as the translator can now replace: - `metro-runtime` is generated like any other package - `asyncRequire`, `HMRClient`, `null-module` and `polyfills/require` gain types and API snapshots. - Eight overrides go: `metro-minify-terser` and `metro-symbolicate` (generated output is equivalent), the five CommonJS worker and extractor modules in `metro-file-map`, and `metro-file-map/src/lib/dependencyExtractor.d.ts`, which had no `.js` beside it and so was never used. - Two stay: `metro-transform-plugins/src/index.d.ts`, because it combines `export type` with `module.exports`, which TypeScript can't express as `export =` without namespace merging; and `crawlers/watchman/planQuery.d.ts`, because the generated output imports types from `fb-watchman`, which has none. Getting there needed a few changes to the generator and to Flow sources, none of which affect runtime behaviour: - Flow comment types (`/*: T */`, `/*:: ... */`) are expanded before translation. The `metro-file-map` workers are loaded in Node without Babel and are typed that way, so the translator saw no annotations at all and emitted `any`. - A `.js.flow` file is used as the Flow source for the adjacent `.js`. That's Flow's own convention, and it types the vendored `eventemitter3` (no `@flow` directive) without an override. - `lintText` returns no result for a path `.eslintignore` covers (`**/vendor/**`), so the generator tolerates that and leaves the output unlinted. - The two `metro-file-map` plugin workers now declare their class and export it by name, rather than exporting an anonymous class expression, which `flowToFlowDef` can't type. - `asyncRequire` exports through an `as AsyncRequire` cast - `flowToFlowDef` drops statics assigned to a function, so `prefetch` and `unstable_importMaybeSync` were otherwise lost. The cast is type-only, and `metro-runtime` already uses `as` casts elsewhere. - `HMRClient._heartbeatTimer` is typed `?ReturnType<typeof setInterval>` in place of Flow's `IntervalID` global, which the translator passes through and TypeScript has no name for. - Generated `.d.ts` no longer run `@typescript-eslint`'s `no-explicit-any` or `no-unused-vars`. Flow checks the sources these are translated from, and an `any` in the output reflects one there; the second rule reports a declaration a CommonJS module exports via `typeof` as unused, which is most of what `metro-runtime` and the `metro-file-map` workers now emit. `no-unused-vars` stays on in the generator's own `--fix` pass, which uses it to drop declarations left unused by translation. `no-empty-object-type` is off too, for now: Flow's inexact `{...}` translates to `{}`, which the rule flags in `polyfills/require.d.ts` - the follow-up diff fixes those annotations at source and turns the rule back on. This replaces the per-file exemption for `metro-file-map/types/flow-types.d.ts`. Changelog: ``` - **[Types]**: Add TypeScript definitions for `metro-runtime` modules, and generate (rather than hand-maintain) types for `metro-file-map` workers ``` Test plan: ``` yarn flow check yarn typecheck-ts yarn build-api-snapshots yarn verify-api-snapshots yarn jest ``` Flow and `tsc` are clean. API snapshots for ES module entry points are unchanged, so removing the overrides changes no public API. `metro-runtime` gains four snapshots, and `metro-minify-terser`'s now reflects its generated definition. Jest: all 150 suites pass, including the `metro` integration tests, which bundle `metro-runtime`.
robhogan
removed this pull request from stack #1997
September 29, 2026 15:13
robhogan
added this pull request to stack #1999
September 29, 2026 15:13
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
flow-api-translator0.332.0 translatesdeclare module.exportsto TypeScript'sexport =(facebook/flow#9491). Until now our.d.tsgenerator rejected any module that used it, which is why nearly all ofmetro-runtimewas excluded, and why most of our hand-written.d.tsoverrides exist.With the
flow-*packages on 0.333.0, this generatesmetro-runtimelike any other package, and removes eight overrides the translator now replaces -metro-minify-terser,metro-symbolicateand six inmetro-file-map(one of which had no.jsbeside it, so was never used).Getting there took a few generator changes, and some light-touch changes to Flow source that don't affect runtime:
/*: T */,/*:: ... */) are expanded before translation, because themetro-file-mapworkers run in Node without Babel. It's a regex, but it seems good enough -flow-parser's WASM build drops Flotate..js.flowis used as the Flow source for an untyped.js, per Flow's own convention. That covers the vendoredeventemitter3.asyncRequireis exported through anas AsyncRequirecast, otherwise translation losesprefetchandunstable_importMaybeSync.Lint on generated
.d.tsis relaxed too:no-unused-varsreports a declaration that a CommonJS module exports viatypeof. It's possible to write Flow that avoids it, but that shouldn't be a concern for Flow authors.no-explicit-any- if one appears, it's because we've already suppressed the equivalent in Flow, so respect that.no-empty-object-typeis more legitimate. Flow's inexact{...}becomes{}, and a follow-up re-enables the rule with better types forrequire.js.Snapshots for the new CommonJS entry points depend on #1988, which teaches API Extractor about
export =.Changelog:
Test plan:
metro-runtimeAPI.md files. Some have messy identifiers, but they effectively capture the public surface..d.tslocally (they're gitignored) and inspect the output.