I've been using React a lot on some recent projects, and enjoying it. The surrounding community and range of libraries on offer is (unsurprisingly) great, and if you're building a common component then it's often easy to find a well-documented open source version of what you're about to build.
You can see this code on GitHub, and it's also deployed to Netlify.
One tool I can no longer live without is [Flow][flow], a static type checker. It helps me spot errors with passing objects that might be incompatible, accessing variables that might not exist, and a whole host of other common pitfalls.
This weekend, I've been playing around with writing generically-typed components, that is: components where the type definition takes a parameter that is also a type. One of the most obvious examples is a list, so I'll use that as an example.
By using a type parameter,
<T>, we can define a type that
takes an array of items, and a method that renders a single item. At the
moment, think of `T` as a placeholder: we'll fill it in later.
Here, we're making a component that takes props of type
Props<T>, and ensuring that the type is an object that
defines a readable `key` property. It doesn't do anything too clever: it
renders the items by calling `map` with our `renderItem` property:
Using the component
Once we've defined our `GenericList` component, we can extend it, and define a class that fills in the `T` with a specific type. In this case, we'll make a list of `TodoItem` objects:
And that's about it: our `GenericList` will only typecheck if the objects passed in have a `key` property, and our types will ensure that each item can always be rendered correctly.
Think of the `GenericList` like a contract: given a type `T`, and a function
T => React.Node, we can render a list of any object with `key`
property, and Flow will type check it all.
And that's it... I've written lists, tables, typeahead searches and more, and doing so has felt pleasant. A big thanks has to go to [William Chargin](https://github.com/wchargin) who helped me out when I [raised the question](https://github.com/facebook/flow/issues/7145) of how to do this. Thanks!