Search code examples
reactjstypescriptreact-proptypes

How to use PropTypes with Typescript in React


I am trying to use PropTypes with Typescript but getting errors:

Without typescript I was able to use:

class TodoFilterItem extends Component {
  constructor (props) {
    super(props);

and then at the bottom

TodoFilterItem.propTypes = {
  name: PropTypes.string,
  filter: PropTypes.string,
  filterTodos: PropTypes.any
}

and that worked for just having PropTypes (i.e. no typescript).

However when I add Typescript and I have

class TodoFilterItem extends Component<ITodoFilterItem> {
  constructor (props:ITodoFilterItem) {
    super(props);
    ...

I have props as an interface like this:

interface ITodoFilterItem  {
  filter: string,
  name: string,
  filterTodos: any
}

and I use the same propTypes:

TodoFilterItem.propTypes = {
  filter: PropTypes.string,
  name: PropTypes.string,
  filterTodos: PropTypes.any
}

I get an error

Property 'propTypes' does not exist on type 'typeof import("/my_adrs/node_modules/@types/prop-types/index")'.  

How to address this and be able to use PropTypes with Typescript in React ?


Solution

  • PropTypes are separate from Typescript. To reuse your propTypes you have to convert it to an interface or type.

    This

    TodoFilterItem.propTypes = {
      filter: PropTypes.string,
      name: PropTypes.string,
      filterTodos: PropTypes.any
    }
    

    becomes

    interface ITodoFilterItem {
      filter: string;
      name: string;
      filterTodos: any; 
    }
    

    Using that interface is simple, you replace TodoFilterItemProps with ITodoFilterItem.

    The convention is to name your component props IProps. Putting that together your component now looks like:

    interface IProps { 
     name: string;
     filter: string;
     filterTodos: any; 
    }
    
    class TodoFilterItem extends Component<IProps> {
      constructor (props:IProps) {
        super(props);
        ...
    

    Note on any

    Try to avoid typing to any. any type is the same has untyped. I imagine filterTodos is an array of todos. If that's the case you can create a type for todo call it

    type Todo = { ...properties of a todo } 
    

    then type filterTodos to be an array of Todo which would look like this:

    type Todo = { 
      name: string,
      status: 'not started' | 'in progress' | 'done'
    }
    
    interface IProps { 
      filter: string;
      name: string;
      filterTodos: Todo[]; 
    }