Flow报错:IDefaultSettings缺索引器属性,求技术解答
Let’s break down why you’re hitting this error and walk through practical fixes.
The Root Cause
When you use Object.entries(defaultSettings), Flow infers the key’s type as a generic string—even though we know the keys can only be 'Drivers' or 'Options' from the IDefaultSettings interface.
Flow’s type system doesn’t track the exact literal values of keys returned by Object.entries (or Object.keys) for object types without an index signature. So when you try to assign settings[key] = setting, Flow sees key as any arbitrary string, and since IDefaultSettings doesn’t allow unrestricted string keys, it throws the error.
This happens even though both variables are typed as IDefaultSettings—the loop introduces a dynamic key that Flow can’t guarantee matches only the defined properties in the interface.
Solutions
1. Narrow the Key Type with Flow’s $Keys Utility
Explicitly tell Flow that the keys are exactly the ones defined in IDefaultSettings using the $Keys utility type and a type assertion:
/* @flow */ interface IDefaultSettings { Drivers?: {}, Options?: {} } const defaultSettings: IDefaultSettings = { Drivers: {}, Options: {} } const settings: IDefaultSettings = {}; mergeSettings(settings); function mergeSettings(settings: IDefaultSettings) { // Narrow keys to the exact literal types from the interface const keys = Object.keys(defaultSettings) as $Keys<IDefaultSettings>[]; for (const key of keys) { switch(key) { case 'Drivers': case 'Options': settings[key] = defaultSettings[key]; break; } } }
By asserting keys as $Keys<IDefaultSettings>[], Flow now knows key can only be 'Drivers' or 'Options', making the assignment safe without an indexer.
2. Add an Index Signature (Less Strict)
If you don’t mind loosening type safety slightly, add an index signature to IDefaultSettings to allow arbitrary string keys that return {} or undefined:
/* @flow */ interface IDefaultSettings { Drivers?: {}, Options?: {}, // Allow any string key with an optional {} value [key: string]: {} | void } const defaultSettings: IDefaultSettings = { Drivers: {}, Options: {} } const settings: IDefaultSettings = {}; mergeSettings(settings); function mergeSettings(settings: IDefaultSettings) { for (const [key, setting] of Object.entries(defaultSettings)) { switch(key) { case 'Drivers': case 'Options': settings[key] = setting; break; } } }
Note: This lets you add any string key to IDefaultSettings objects, which may not be ideal if you want to enforce only the two defined properties.
3. Assign Properties Directly (Most Explicit)
For a small number of properties, skip the loop and assign each property directly. This eliminates dynamic keys entirely, making it the most type-safe approach:
/* @flow */ interface IDefaultSettings { Drivers?: {}, Options?: {} } const defaultSettings: IDefaultSettings = { Drivers: {}, Options: {} } const settings: IDefaultSettings = {}; mergeSettings(settings); function mergeSettings(settings: IDefaultSettings) { settings.Drivers = defaultSettings.Drivers; settings.Options = defaultSettings.Options; }
Flow can verify each assignment directly against the interface, so no error is thrown.
4. Use a Type Guard for the Key
Create a type guard function to check if the key is one of the allowed values, which narrows the type for Flow:
/* @flow */ interface IDefaultSettings { Drivers?: {}, Options?: {} } type SettingsKey = 'Drivers' | 'Options'; // Type guard to confirm key is valid function isSettingsKey(key: string): key is SettingsKey { return key === 'Drivers' || key === 'Options'; } const defaultSettings: IDefaultSettings = { Drivers: {}, Options: {} } const settings: IDefaultSettings = {}; mergeSettings(settings); function mergeSettings(settings: IDefaultSettings) { for (const [key, setting] of Object.entries(defaultSettings)) { if (isSettingsKey(key)) { settings[key] = setting; } } }
The type guard tells Flow that if the function returns true, key is definitely a valid SettingsKey, making the assignment safe.
内容的提问来源于stack exchange,提问作者darkkenergy

