Home

Awesome

build status dependency status npm downloads

Features

Compatibility

tcomb-react has been tested and found working on the following targets. The list is not exhaustive and tcomb-react will probably work on other versions that haven't been listed.

React: ^0.13.0, ^0.14.0, ^15.0.0

Prop types

The @props decorator (ES7)

For an equivalent implementation in ES5, or for Stateless Components, 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

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

Signature

Same as @props.

Stateless Component Example

import { propTypes } from 'tcomb-react'

const MyComponentProps = t.interface({
  name: t.String,
});

const MyComponent = (props) => (
  <div />
);
MyComponent.propTypes = propTypes(MyComponentProps);

ES5 React.createClass Example

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>) => Object

Example

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) => string

Example

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 here

Augmented pre-defined types

tcomb-react exports some useful pre-defined types:

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:

Comparison table

TypeReacttcomb-react
arrayarrayArray
booleanboolBoolean
functionsfuncFunction
numbersnumberNumber
objectsobjectObject
stringsstringString
allanyAny
required propT.isRequiredT
optional propTmaybe(T)
custom types
tuplestuple([T, U, ...])
listsarrayOf(T)list(T)
instanceinstanceOf(A)T
dictionariesobjectOf(T)dict(T, U) (keys are checked)
enumsoneOf(['a', 'b'])enums.of('a b')
unionsoneOfType([T, U])union([T, U])
duck typingshapeinterface
react elementelementReactElement
react nodenodeReactNode
react childReactChild
react childrenReactChildren