Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flowtype: indexer property is missing in

Tags:

flowtype

Given the following code:

/* @flow */
interface IDefaultSettings {
  Drivers?: {},
  Options?: {}
}

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;
    }
  }
}

Place above code in the Flow playgound to try this out.

I'm receiving this lint error, and unable to solve: "Cannot assign `setting` to `settings[key]` because an indexer property is missing in `IDefaultSettings` [1]."

Why would the use of key need an indexer prop in the interface, IDefaultSettings, when this code is pulling key from an object with a known interface - I mean, what else could key be? Both objects, defaultSettings & settings are of the same type/structure, IDefaultSettings.

Help please & thanks!

like image 631
darkkenergy Avatar asked Mar 23 '18 21:03

darkkenergy


Video Answer


1 Answers

I'm not sure why you've chosen to use interface over type, although its not the specific reason for the problem. It does mean that flow can't determine what property names are valid. Note that flow isn't very good at this, but its partly due to the fact it's a static type checker, so anything in a variable can't be comprehensively compared.

If we switch to type we get rid of the indexer property error, but introduce a new one, which is that the return type from Object.entries is a tuple where the value is of type mixed.

Your IDefaultSettings has two keys with object values, so flow balks at the idea they could be something else. A solution, although a bit of hack, is to cast the value via any. Or alternatively, use the $FlowFixMe comment syntax and document why your muting the error.

type IDefaultSettings = {
  Drivers?: {},
  Options?: {}
}

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: any);
        break;
    }
  }
}

(Try)

like image 102
Dave Meehan Avatar answered Oct 19 '22 20:10

Dave Meehan