tcomb-react

    0.9.3 • Public • Published

    build status dependency status npm downloads

    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

    • type can be a map string -> TcombType, a tcomb struct, a tcomb interface, a refinement of a tcomb struct, a refinement of a tcomb interface
    • options:
      • strict: boolean (default true) if true checks 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>) => 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:

    • ReactElement
    • ReactNode
    • ReactChild
    • ReactChildren

    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:

    • ReactElementT
    • ReactNodeT
    • ReactChildT
    • ReactChildrenT

    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

    Install

    npm i tcomb-react

    DownloadsWeekly Downloads

    7,652

    Version

    0.9.3

    License

    MIT

    Last publish

    Collaborators

    • gcanti