1. Type-check components with TypeScript
Type-checking is essential for positive developer experience and optimized code collaboration - it what makes your reusable code easy to use and maintain.
Why TypeScript (or, why not prop-types)?
TS and prop-types are not alone in this game but they are certainly the most popular. The two are different in the way they operate and even in the way they're used (TS validates types at compile-time, whereas prop-types performs at runtime) - nevertheless, it is a fact of reality that the two are rarely used on the same project. That isn't surprising as the two do overlap quite considerably in the way they're used - and, with all due respect to dev ex, there's still a product to deliver.
If you ever used TypeScript you know it serves a much greater role than prop-types. It offers intelligent code suggestions in supported IDEs, it shortens useful and otherwise cumbersome JS code (e.g, Enums) and in general, once you get the hang of it, it shows its strengths by saving time in fixing bugs or simply figuring out your teammates' code.
Moreover, TS is trending and may even become the new standard for web development. That certainly makes it something worth investing your time and effort.
When using tools to collaborate on components across repositories (e.g, shared Bit components or even Git Submodules, TS really shows its strengths by providing component consumers with a clear API, and component collaborators with a more explicit and intelligible code.
2. Defining Props & Event is Not Enough
Components should be typed as well; otherwise, implicit assumptions are not communicated to TS and unwanted errors start to appear.
For example, a functional component should be types like so:
const AComponent: React.FC<IProps> = (props : IProps) => {...}
Otherwise, TS will not expect the ‘children’ prop or a return type that must be assignable to JSX.Element
For example (an un-typed component):
Used like so:
function App() {
return (
<div className="App">
<Button color='day'>a lable!</ButtonA>
</div>
);
}
Will produce an error, informing you that 'children' were not expected:
Type '{ children: string; color: "day"; }' is not assignable to type 'IntrinsicAttributes & IButtonProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & IButtonProps'.
3. Write React with TS to Auto Generate Docs
Auto doc-generation is another great thing you can expect to enjoy when using TS (but in that case, also with prop-types). To make that happen, make sure you define your components' type/interface both as a generic of React.FC<T>
and (directly) as the function's argument type. Otherwise, your props would simply not be included in the generated docs (at least not when using react-docgen / Bit.dev)
For example:
Moreover, make sure to complement your TS with descriptions written using the JSDocs syntax.
For Example, this:
Will generate this:
Check out React-docgen playground
4. Extend Native-HTML-like Components with React's Interfaces
Before we start, two files you should definitely get familiar with are: React's index.d.ts and the global.d.ts files.
They're both installed when you add React to your project (if you used npm, you'll find them inside the npm_modules/@types/react folder.
These files contain type and interface definitions used and offered by React, so if you need to extend a native-HTML-like component - that is where you'd find it.
For example, let's say I have a Button component that behaves, more or less, like a native HTML button element (e.g., it can have a label, it has a 'disable' prop, etc.). I can and should enjoy all the implicit definitions that come with such a component, using React's types.
Conclusion
This post is far from being a comprehensive guide to building reusable components but I do hope I've managed to clear up a few important issues. React with TypeScript, together with the right tools for component collaboration, offer a great way to increase collaboration and build a more maintainable and scalable code.
Top comments (2)
const AComponent: React.FC<IProps> = (props : IProps) => {...}
You don't need
(props : IProps)
when useReact.FC<IProps>
.You are right but as I've mentioned in this post, bit.dev and react-docgen will not document these props unless they are written that way (and as it is a guide to shareable components, documentation is critical).