Skip to content

Commit 9d80599

Browse files
robhoganfacebook-github-bot
authored andcommitted
Strengthen Flow typing around config objects
Summary: Make `InputConfigT` read-only at top-level (note that this is already the case in TypeScript), and nested objects of `WatcherConfigT` read-only, consistent with `ResolverConfigT`, etc. This removes a bunch of issues around passing `ConfigT` as an `InputConfigT` and makes several internal uses of `mergeConfig` and `runServer` type-safe. Changelog: Internal Reviewed By: huntie Differential Revision: D62707211 fbshipit-source-id: 6dda78cf31fe504480ac6fff777bbb66b5f8bd05
1 parent 7d02e17 commit 9d80599

File tree

3 files changed

+37
-59
lines changed

3 files changed

+37
-59
lines changed

packages/metro-config/src/configTypes.flow.js

+24-22
Original file line numberDiff line numberDiff line change
@@ -195,37 +195,39 @@ type SymbolicatorConfigT = {
195195

196196
type WatcherConfigT = {
197197
additionalExts: $ReadOnlyArray<string>,
198-
healthCheck: {
198+
healthCheck: $ReadOnly<{
199199
enabled: boolean,
200200
interval: number,
201201
timeout: number,
202202
filePrefix: string,
203-
},
203+
}>,
204204
unstable_workerThreads: boolean,
205-
watchman: {
205+
watchman: $ReadOnly<{
206206
deferStates: $ReadOnlyArray<string>,
207-
},
207+
}>,
208208
};
209209

210-
export type InputConfigT = Partial<{
211-
...MetalConfigT,
212-
...$ReadOnly<{
213-
cacheStores:
214-
| $ReadOnlyArray<CacheStore<TransformResult<>>>
215-
| (MetroCache => $ReadOnlyArray<CacheStore<TransformResult<>>>),
216-
resolver: $ReadOnly<Partial<ResolverConfigT>>,
217-
server: $ReadOnly<Partial<ServerConfigT>>,
218-
serializer: $ReadOnly<Partial<SerializerConfigT>>,
219-
symbolicator: $ReadOnly<Partial<SymbolicatorConfigT>>,
220-
transformer: $ReadOnly<Partial<TransformerConfigT>>,
221-
watcher: $ReadOnly<
222-
Partial<{
223-
...WatcherConfigT,
224-
healthCheck?: $ReadOnly<Partial<WatcherConfigT['healthCheck']>>,
225-
}>,
226-
>,
210+
export type InputConfigT = $ReadOnly<
211+
Partial<{
212+
...MetalConfigT,
213+
...$ReadOnly<{
214+
cacheStores:
215+
| $ReadOnlyArray<CacheStore<TransformResult<>>>
216+
| (MetroCache => $ReadOnlyArray<CacheStore<TransformResult<>>>),
217+
resolver: $ReadOnly<Partial<ResolverConfigT>>,
218+
server: $ReadOnly<Partial<ServerConfigT>>,
219+
serializer: $ReadOnly<Partial<SerializerConfigT>>,
220+
symbolicator: $ReadOnly<Partial<SymbolicatorConfigT>>,
221+
transformer: $ReadOnly<Partial<TransformerConfigT>>,
222+
watcher: $ReadOnly<
223+
Partial<{
224+
...WatcherConfigT,
225+
healthCheck?: $ReadOnly<Partial<WatcherConfigT['healthCheck']>>,
226+
}>,
227+
>,
228+
}>,
227229
}>,
228-
}>;
230+
>;
229231

230232
export type MetroConfig = InputConfigT;
231233

packages/metro-config/src/loadConfig.js

+13-31
Original file line numberDiff line numberDiff line change
@@ -196,22 +196,18 @@ async function loadMetroConfigFromDisk(
196196
const rootPath = dirname(filepath);
197197

198198
const defaults = await getDefaultConfig(rootPath);
199-
// $FlowFixMe[incompatible-variance]
200-
// $FlowFixMe[incompatible-call]
199+
201200
const defaultConfig: ConfigT = mergeConfig(defaults, defaultConfigOverrides);
202201

203202
if (typeof configModule === 'function') {
204203
// Get a default configuration based on what we know, which we in turn can pass
205204
// to the function.
206205

207206
const resultedConfig = await configModule(defaultConfig);
208-
// $FlowFixMe[incompatible-call]
209-
// $FlowFixMe[incompatible-variance]
207+
210208
return mergeConfig(defaultConfig, resultedConfig);
211209
}
212210

213-
// $FlowFixMe[incompatible-variance]
214-
// $FlowFixMe[incompatible-call]
215211
return mergeConfig(defaultConfig, configModule);
216212
}
217213

@@ -220,17 +216,21 @@ function overrideConfigWithArguments(
220216
argv: YargArguments,
221217
): ConfigT {
222218
// We override some config arguments here with the argv
223-
224-
const output: InputConfigT = {
219+
const output: {
220+
// Spread to remove invariance so that `output` is mutable.
221+
...Partial<ConfigT>,
222+
resolver: {...Partial<ConfigT['resolver']>},
223+
serializer: {...Partial<ConfigT['serializer']>},
224+
server: {...Partial<ConfigT['server']>},
225+
transformer: {...Partial<ConfigT['transformer']>},
226+
} = {
225227
resolver: {},
226228
serializer: {},
227229
server: {},
228230
transformer: {},
229231
};
230232

231233
if (argv.port != null) {
232-
// $FlowFixMe[incompatible-use]
233-
// $FlowFixMe[cannot-write]
234234
output.server.port = Number(argv.port);
235235
}
236236

@@ -243,20 +243,14 @@ function overrideConfigWithArguments(
243243
}
244244

245245
if (argv.assetExts != null) {
246-
// $FlowFixMe[incompatible-use]
247-
// $FlowFixMe[cannot-write]
248246
output.resolver.assetExts = argv.assetExts;
249247
}
250248

251249
if (argv.sourceExts != null) {
252-
// $FlowFixMe[incompatible-use]
253-
// $FlowFixMe[cannot-write]
254250
output.resolver.sourceExts = argv.sourceExts;
255251
}
256252

257253
if (argv.platforms != null) {
258-
// $FlowFixMe[incompatible-use]
259-
// $FlowFixMe[cannot-write]
260254
output.resolver.platforms = argv.platforms;
261255
}
262256

@@ -265,8 +259,6 @@ function overrideConfigWithArguments(
265259
}
266260

267261
if (argv.transformer != null) {
268-
// $FlowFixMe[incompatible-use]
269-
// $FlowFixMe[cannot-write]
270262
output.transformer.babelTransformerPath = argv.transformer;
271263
}
272264

@@ -283,8 +275,6 @@ function overrideConfigWithArguments(
283275
// TODO: Ask if this is the way to go
284276
}
285277

286-
// $FlowFixMe[incompatible-variance]
287-
// $FlowFixMe[incompatible-call]
288278
return mergeConfig(config, output);
289279
}
290280

@@ -319,19 +309,11 @@ async function loadConfig(
319309
// Override the configuration with cli parameters
320310
const configWithArgs = overrideConfigWithArguments(configuration, argv);
321311

322-
const overriddenConfig: {[string]: mixed} = {};
323-
324-
overriddenConfig.watchFolders = [
325-
configWithArgs.projectRoot,
326-
...configWithArgs.watchFolders,
327-
];
328-
329312
// Set the watchfolders to include the projectRoot, as Metro assumes that is
330313
// the case
331-
// $FlowFixMe[incompatible-variance]
332-
// $FlowFixMe[incompatible-indexer]
333-
// $FlowFixMe[incompatible-call]
334-
return mergeConfig(configWithArgs, overriddenConfig);
314+
return mergeConfig(configWithArgs, {
315+
watchFolders: [configWithArgs.projectRoot, ...configWithArgs.watchFolders],
316+
});
335317
}
336318

337319
module.exports = {

packages/metro/src/index.flow.js

-6
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,6 @@ export type {MetroConfig};
134134

135135
async function getConfig(config: InputConfigT): Promise<ConfigT> {
136136
const defaultConfig = await getDefaultConfig(config.projectRoot);
137-
// $FlowFixMe[incompatible-variance]
138-
// $FlowFixMe[incompatible-call]
139137
return mergeConfig(defaultConfig, config);
140138
}
141139

@@ -191,8 +189,6 @@ const createConnectMiddleware = async function (
191189
config: ConfigT,
192190
options?: RunMetroOptions,
193191
): Promise<MetroMiddleWare> {
194-
// $FlowFixMe[incompatible-variance]
195-
// $FlowFixMe[incompatible-call]
196192
const metroServer = await runMetro(config, options);
197193

198194
let enhancedMiddleware: Middleware = metroServer.processRequest;
@@ -385,8 +381,6 @@ exports.runBuild = async (
385381
map: string,
386382
...
387383
}> => {
388-
// $FlowFixMe[incompatible-variance]
389-
// $FlowFixMe[incompatible-call]
390384
const metroServer = await runMetro(config, {
391385
watch: false,
392386
});

0 commit comments

Comments
 (0)