tcomb-react v0.9.3
Features
- 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
Compatibility
React: ^0.13.0, ^0.14.0, ^15.0.0
Prop types
The @props decorator (ES7)
For an equivalent implementation in ES5 see the propTypes function below.
Signature
type Props = {[key: string]: TcombType};
type PropsType = TcombStruct | TcombInterface;
type Type = Props | PropsType | Refinement<PropsType>;
type Options = {
strict?: boolean // default true
};
@props(type: Type, options?: Options)where
typecan be a mapstring -> TcombType, atcombstruct, atcombinterface, a refinement of atcombstruct, a refinement of atcombinterfaceoptions:strict: boolean(defaulttrue) iftruechecks for unwanted additional props
Example (ES7)
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 (
<div>
<p>{this.props.name}</p>
...
</div>
)
}
}Unwanted additional props
By default tcomb-react checks for unwanted additional props:
@props({
name: t.String
})
class Person extends React.Component {
render() {
return (
<div>
<p>{this.props.name}</p>
</div>
)
}
}
...
<Person name="Giulio" surname="Canti" />Output
Warning: Failed propType: [tcomb] Invalid additional prop(s):
[
"surname"
]
supplied to Person.Note. You can opt-out passing the option argument { strict: false }.
The propTypes function (ES5)
Signature
Same as @props.
Example (ES5)
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 (
<div>
<p>{this.props.name}</p>
...
</div>
);
}
});How it works
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:
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:
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('...');
}
},
}The babel plugin
Using babel-plugin-tcomb you can express propTypes as Flow type annotations:
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<typeof isUrl>;
type Props = {
name: string,
surname: ?string,
age: number,
gender: Gender,
avatar: URL
};
@props(Props)
class Card extends React.Component {
render() {
return (
<div>
<p>{this.props.name}</p>
...
</div>
)
}
}Extract documentation from your components
The parse function
Given a path to a component file returns a JSON / JavaScript blob containing props types, default values and comments.
Signature
(path: string | Array<string>) => ObjectExample
Source
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 (
<div>
<p>{this.props.name}</p>
<p>{this.props.surname}</p>
</div>
)
}
}Usage
import parse from 'tcomb-react/lib/parse'
const json = parse('./components/Card.js')
console.log(JSON.stringify(json, null, 2))Output
{
"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
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 function
Given a JSON / JavaScript blob returned by parse returns a markdown containing the components documentation.
Signature
(json: Object) => stringExample
Usage
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
## Card
Component description here
**Props**
- `name: String` name description here
- `surname: String` (optional, default: `"Canti"`) surname description hereAugmented pre-defined types
tcomb-react exports some useful pre-defined types:
ReactElementReactNodeReactChildReactChildren
Example
import { props, ReactChild } from 'tcomb-react';
@props({
children: ReactChild // only one child is allowed
})
class MyComponent extends React.Component {
render() {
return (
<div>
{this.props.children}
</div>
);
}
}Support for babel-plugin-tcomb
The following types for Flow are exported:
ReactElementTReactNodeTReactChildTReactChildrenT
Comparison table
| 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 |
9 years ago
9 years ago
9 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago