Type checking for React components
npm install tcomb-react

!npm downloads
- by default props are required, a saner default since it's quite easy to forget .isRequired
- checks for unwanted additional props
- documentation (types and comments) can be automatically extracted
- additional fine grained type checks, nestable at arbitrary level
- builds on tcomb, tcomb-validation, tcomb-doc libraries
React: ^0.13.0, ^0.14.0, ^15.0.0
@props decorator (ES7)For an equivalent implementation in ES5 see the propTypes function below.
Signature
``js
type Props = {[key: string]: TcombType};
type PropsType = TcombStruct | TcombInterface;
type Type = Props | PropsType | Refinement
type Options = {
strict?: boolean // default true
};
@props(type: Type, options?: Options)
`
where
- type can be a map string -> TcombType, a tcomb struct, a tcomb interface, a refinement of a tcomb struct, a refinement of a tcomb interfaceoptions
- :strict: boolean
- (default true) if true checks for unwanted additional props
Example (ES7)
`js
import t from 'tcomb'
import { props } from 'tcomb-react'
const Gender = t.enums.of(['Male', 'Female'], 'Gender')
const URL = t.refinement(t.String, (s) => s.startsWith('http'), 'URL')
@props({
name: t.String, // a required string
surname: t.maybe(t.String), // an optional string
age: t.Number, // a required number
gender: Gender, // an enum
avatar: URL // a refinement
})
class Card extends React.Component {
render() {
return (
{this.props.name}
}
`
Unwanted additional props
By default tcomb-react checks for unwanted additional props:
`js
@props({
name: t.String
})
class Person extends React.Component {
render() {
return (
{this.props.name}
}
...
`
Output
`
Warning: Failed propType: [tcomb] Invalid additional prop(s):
[
"surname"
]
supplied to Person.
`
Note. You can opt-out passing the option argument { strict: false }.
function (ES5)Signature
Same as @props.
Example (ES5)
`js
var t = require('tcomb');
var propTypes = require('tcomb-react').propTypes;
var Gender = t.enums.of(['Male', 'Female'], 'Gender');
var URL = t.refinement(t.String, function (s) { return s.startsWith('http'); }, 'URL');
var Card = React.createClass({
propTypes: propTypes({
name: t.String, // a required string
surname: t.maybe(t.String), // an optional string
age: t.Number, // a required number
gender: Gender, // an enum
avatar: URL // a refinement
}),
render: function () {
return (
{this.props.name}
});
`
The @props decorator sets propTypes on the target component to use a custom validator function built around tcomb types for each specified prop.
For example, the following:
`js
const URL = t.refinement(t.String, (s) => s.startsWith('http'), 'URL');
@props({
name: t.String,
url: URL,
})
class MyComponent extends React.Component {
// ...
}
`
is roughly equivalent to:
`js
const URL = t.refinement(t.String, (s) => s.startsWith('http'), 'URL');
class MyComponent extends React.Component {
// ...
}
MyComponent.propTypes = {
name: function(props, propName, componentName) {
if (!t.validate(props[propName], t.String).isValid()) {
return new Error('...');
}
},
url: function(props, propName, componentName) {
if (!t.validate(props[propName], URL).isValid()) {
return new Error('...');
}
},
}
`
Using babel-plugin-tcomb you can express propTypes as Flow type annotations:
`js
import React from 'react'
import ReactDOM from 'react-dom'
import type { $Refinement } from 'tcomb'
import { props } from 'tcomb-react'
type Gender = 'Male' | 'Female';
const isUrl = (s) => s.startsWith('http')
type URL = string & $Refinement
type Props = {
name: string,
surname: ?string,
age: number,
gender: Gender,
avatar: URL
};
@props(Props)
class Card extends React.Component {
render() {
return (
{this.props.name}
}
`
functionGiven a path to a component file returns a JSON / JavaScript blob containing props types, default values and comments.
Signature
`js`
(path: string | Array
Example
Source
`js
import t from 'tcomb'
import { props } from 'tcomb-react'
/**
* Component description here
* @param name - name description here
* @param surname - surname description here
*/
@props({
name: t.String, // a required string
surname: t.maybe(t.String) // an optional string
})
export default class Card extends React.Component {
static defaultProps = {
surname: 'Canti' // default value for surname prop
}
render() {
return (
{this.props.name}
{this.props.surname}
Usage
`js
import parse from 'tcomb-react/lib/parse'
const json = parse('./components/Card.js')
console.log(JSON.stringify(json, null, 2))
`Output
`json
{
"name": "Card",
"description": "Component description here",
"props": {
"name": {
"kind": "irreducible",
"name": "String",
"required": true,
"description": "name description here"
},
"surname": {
"kind": "irreducible",
"name": "String",
"required": false,
"defaultValue": "Canti",
"description": "surname description here"
}
}
}
`Note. Since
parse uses runtime type introspection, your components should be requireable from your script (you may be required to shim the browser environment).Parsing multiple components
`js
import parse from 'tcomb-react/lib/parse'
import path from 'path'
import glob from 'glob'function getPath(file) {
return path.resolve(process.cwd(), file);
}
parse(glob.sync('./components/*.js').map(getPath));
`The
toMarkdown functionGiven a JSON / JavaScript blob returned by
parse returns a markdown containing the components documentation.Signature
`js
(json: Object) => string
`Example
Usage
`js
import parse from 'tcomb-react/lib/parse'
import toMarkdown from 'tcomb-react/lib/toMarkdown'
const json = parse('./components/Card.js')
console.log(toMarkdown(json));
`Output
`markdown
Card
Component description here
Props
-
name: String name description here
- surname: String (optional, default: "Canti") surname description here`Augmented pre-defined types
tcomb-react exports some useful pre-defined types:-
ReactElement
- ReactNode
- ReactChild
- ReactChildrenExample
`js
import { props, ReactChild } from 'tcomb-react';@props({
children: ReactChild // only one child is allowed
})
class MyComponent extends React.Component {
render() {
return (
{this.props.children}
);
}}
`Support for babel-plugin-tcomb
The following types for Flow are exported:
-
ReactElementT
- ReactNodeT
- ReactChildT
- ReactChildrenT`| Type | React | tcomb-react |
|------|-------|-------------|
| array | array | Array |
| boolean | bool | Boolean |
| functions | func | Function |
| numbers | number | Number |
| objects | object | Object |
| strings | string | String |
| all | any | Any |
| required prop | T.isRequired | T |
| optional prop | T | maybe(T) |
| custom types | ✘ | ✓ |
| tuples | ✘ | tuple([T, U, ...]) |
| lists | arrayOf(T) | list(T) |
| instance | instanceOf(A) | T |
| dictionaries | objectOf(T) | dict(T, U) (keys are checked) |
| enums | oneOf(['a', 'b']) | enums.of('a b') |
| unions | oneOfType([T, U]) | union([T, U]) |
| duck typing | shape | struct |
| react element | element | ReactElement |
| react node | node | ReactNode |
| react child | ✘ | ReactChild |
| react children | ✘ | ReactChildren |