Flow: Typing nested objects?

Created on 16 Sep 2017  路  6Comments  路  Source: facebook/flow

In Flow, we currently have $PropertyType, which has been a savior. However, I'm struggling with typing nested objects. I have to deal with a ton of flow types that I don't control (they're auto generated types from a GraphQL schema).

I know we can wrap $PropertyTypes around each other. But after enough nested objects, this solution isn't very readable. I searched around for a good while but can't seem to find much on this use-case. Maybe I'm just a dummy and I'm missing something obvious.

Take this example:

type Article = {
  title: string,
  author: {
    name: string,
    location: {
      city: string,
      state: string,
      zip: number
    }
  }
}

const article: Article = {
  title: 'foo',
  author: {
    name: 'Joe',
    location: {
      city: 'Los Angeles',
      state: 'CA',
      zip: 12345,
      geo: {
        lat: 123,
        long: 123
      }
    }
  }
}

Currently, to type article.author.location, I have to do this:

const location: $PropertyType<$PropertyType<Article, 'author'>, 'location'> = article.author.location;

To type article.author.location.geo:

const geo: $PropertyType<$PropertyType<$PropertyType<Article, 'author'>, 'location'>, 'geo'> = article.author.location.geo;

Something like this would be more ideal:

// #1
const location: Article.author.location = article.author.location;

// #2
const location: $PropertyType<Article, 'author.location'> = article.author.location;

Anyone know of a more readable or maintainable solution?

feature request

Most helpful comment

docs describe a pattern to get nested types using $Call

https://flow.org/en/docs/types/utilities/#toc-propertytype

it is not so straightforward either

// Extracting deeply nested types:
type NestedObj = {|
  +status: ?number,
  +data: ?$ReadOnlyArray<{|
    +foo: ?{|
       +bar: number,
    |},
  |}>,
|};

// If you wanted to extract the type for `bar`, you could use $Call:
type BarType = $Call<
  <T>({
    +data: ?$ReadOnlyArray<{
      +foo: ?{
        +bar: ?T
      },
    }>,
  }) => T,
  NestedObj,
>;

All 6 comments

Really want this if there's no solution to get type inference working in mapStateToProps from react-redux without explicitly re-typing the deeply accessed values from my RootState type via idx.

See #5056 for reference issue for my previous comment.

docs describe a pattern to get nested types using $Call

https://flow.org/en/docs/types/utilities/#toc-propertytype

it is not so straightforward either

// Extracting deeply nested types:
type NestedObj = {|
  +status: ?number,
  +data: ?$ReadOnlyArray<{|
    +foo: ?{|
       +bar: number,
    |},
  |}>,
|};

// If you wanted to extract the type for `bar`, you could use $Call:
type BarType = $Call<
  <T>({
    +data: ?$ReadOnlyArray<{
      +foo: ?{
        +bar: ?T
      },
    }>,
  }) => T,
  NestedObj,
>;

anyways, something like const location: Article.author.location = article.author.location; would be so useful!

@mrkev I think this would be much like the implementation of idx type

this would also make simpler to type lodash ._get

https://github.com/facebook/flow/issues/5767

I'm having the same problem typing redux states with nested properties. At first glance, an easy answer to both of our problems is to just break up the type definitions even further.

Original

type Article = {
  title: string,
  author: {
    name: string,
    location: {
      city: string,
      state: string,
      zip: number
    }
  }
}

Revised

type Article = {
  title: string,
  author: ArticleAuthor
}

type ArticleAuthor = {
  name: string,
  location: ArticleAuthorLocation,
}

type ArticleAuthorLocation = {
  city: string,
  state: string,
  zip: string,
}

But there's no denying that the proposal would be way more ideal for most use cases.
const location: Article.author.location = article.author.location

Was this page helpful?
0 / 5 - 0 ratings