4

Trying to setup Flow in my project, but don't really understand how to work with Immutable records. I want to statically check component props, here is how I'm doing it:

// @flow

import React from "react";
import {render} from "react-dom";
import * as I from "immutable";

const Person = I.Record({
  name: null,
});

type Props = {
  data: Person,
};

const PersonInfo = (props: Props) => {
  const {data} = props;
  return (
    <span>
      Name: {data.name}
    </span>
  );
};

render(
  <PersonInfo data={1} />, // I would expect to get some compile error here
  document.getElementById("app")
);

I also added immutable.js.flow in the project and .flowconfig.

1 Answers1

1

This is actually an issue with the Immutable.js type definition. It always returns an any type. Basically meaning Records aren't typechecked. I went into the reason why records are so loosly defined here. The gist of it is, Flow doesn't support intersect-types with objects yet (which the type of a record would have to be). But you can override the Record type with the more restrictive type definition describedd in this answer. I copied it over:

declare class Record<T: Object> {
  static <T: Object>(spec: T, name?: string): Record<T>;
  get: <A>(key: $Keys<T>) => A;
  set<A>(key: $Keys<T>, value: A): Record<T>;
  remove(key: $Keys<T>): Record<T>;
}

If you add this decleration as a local decleration, you won't be able to access the properties directly anymore (like you did with data.name), but will have to use the get function like this data.get('name'). IMO the downside of this definition is pretty minor, compared to the added type savety. Now sadly, due to other restrictions in the language, the types of the values aren't typechecked, as illustrated in this example.

Sadly there is no good solution for stronly typed immutable data structures in Flow yet. The features, required to make this perfect are pretty much on the roadmap for Flow though.

TL;DR

Records aren't typechecked, due to restrictions in the language. But you can improve typechecking by using the declaration provided above.

Community
  • 1
  • 1
halbgut
  • 2,368
  • 17
  • 22
  • Do you know if the TypeScript is any better in this case? – Liubomyr Mykhalchenko Sep 25 '16 at 16:23
  • 1
    For the most part TypeScript's type system is inferior to Flow's and that is delibrate on TypeScript's part. So **no, it's actually worse**. See [TypeScript definition](https://github.com/facebook/immutable-js/blob/master/type-definitions/Immutable.d.ts#L1133) & [Flow definition](https://github.com/facebook/immutable-js/blob/master/type-definitions/immutable.js.flow#L622) of the `Record`. As I said, the Flow definition is far from perfect. But the features required for a perfect definition are on Flow's roadmap, while they aren't on TypeScript's. IMHO, these are unlikely to come to TypeScript. – halbgut Sep 25 '16 at 18:54
  • 1
    @Liubko [this](https://discuss.reactjs.org/t/if-typescript-is-so-great-how-come-all-notable-reactjs-projects-use-babel/4887/2) might also interest you. It's a cursory explaination of the differences. – halbgut Sep 25 '16 at 19:31
  • This really makes me consider using scala.js. – jhegedus Oct 30 '16 at 20:55
  • @jhegedus similarly to Elm, the reasons why I'm sticking to options closer to JS are (1) low entry barrier and (2) it's easier to tap into the fast NPM ecosystem (the second point being the most important reason for me personally). – halbgut Oct 31 '16 at 14:01
  • what do you mean fast npm ecosystem ? you mean server side ? – jhegedus Oct 31 '16 at 16:31
  • damn it! I meant vast. – halbgut Oct 31 '16 at 21:51