or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

code-style-rules.mdcomponent-lifecycle-rules.mdindex.mdjsx-syntax-rules.mdplugin-configuration.mdprop-validation-rules.mdreact-component-rules.mdsecurity-safety-rules.md
tile.json

prop-validation-rules.mddocs/

Prop Types and Validation Rules

Rules for PropTypes usage, prop validation, and type safety in React components. These rules ensure proper component interfaces and help catch prop-related errors during development.

Capabilities

PropTypes Definition Rules

Rules for defining and using PropTypes in React components.

const propTypesRules = {
  /** Prevent missing props validation in React component definition */
  'react/prop-types': ESLintRule;
  /** Enforce all defaultProps have a corresponding non-required PropType */
  'react/default-props-match-prop-types': ESLintRule;
  /** Enforce a defaultProps definition for every prop that is not required */
  'react/require-default-props': ESLintRule;
  /** Prevent unused propTypes */
  'react/no-unused-prop-types': ESLintRule;
  /** Forbid certain propTypes */
  'react/forbid-prop-types': ESLintRule;
};

Usage Examples:

import PropTypes from 'prop-types';

// ✓ Good - Component with proper PropTypes
const UserCard = ({ name, age, email, isActive }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
      {isActive && <span>Active User</span>}
    </div>
  );
};

UserCard.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  email: PropTypes.string,
  isActive: PropTypes.bool
};

UserCard.defaultProps = {
  email: '',
  isActive: false
};

// ✗ Bad - Missing PropTypes
const UserCard = ({ name, age, email, isActive }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>Age: {age}</p>
    </div>
  );
};
// No PropTypes defined

// ✗ Bad - PropTypes don't match defaultProps
const MyComponent = ({ title, count }) => <div>{title}: {count}</div>;

MyComponent.propTypes = {
  title: PropTypes.string.isRequired,
  count: PropTypes.number
};

MyComponent.defaultProps = {
  title: 'Default', // Error: title is required but has default
  count: 0,
  extra: 'unused' // Error: extra not in PropTypes
};

PropTypes Organization Rules

Rules for organizing and sorting PropTypes definitions.

const propTypesOrganizationRules = {
  /** Enforce propTypes declarations alphabetical sorting */
  'react/sort-prop-types': ESLintRule;
  /** Enforce defaultProps declarations alphabetical sorting */
  'react/sort-default-props': ESLintRule;
  /** Enforce JSX default props alphabetical sorting */
  'react/jsx-sort-default-props': ESLintRule;
};

Usage Examples:

// ✓ Good - PropTypes in alphabetical order
MyComponent.propTypes = {
  age: PropTypes.number,
  email: PropTypes.string,
  name: PropTypes.string.isRequired,
  role: PropTypes.oneOf(['admin', 'user'])
};

MyComponent.defaultProps = {
  age: 0,
  email: '',
  role: 'user'
};

// ✗ Bad - PropTypes not alphabetically sorted
MyComponent.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number,
  role: PropTypes.oneOf(['admin', 'user']),
  email: PropTypes.string
};

MyComponent.defaultProps = {
  role: 'user',
  age: 0,
  email: ''
};

PropTypes Restrictions

Rules for restricting certain PropTypes patterns that can lead to issues.

const propTypesRestrictionRules = {
  /** Forbid certain propTypes (any, array, object) */
  'react/forbid-prop-types': ESLintRule;
  /** Forbid foreign propTypes */
  'react/forbid-foreign-prop-types': ESLintRule;
  /** Prevent object type as default prop */
  'react/no-object-type-as-default-prop': ESLintRule;
  /** Enforce exact prop types */
  'react/prefer-exact-props': ESLintRule;
  /** Enforce read-only props */
  'react/prefer-read-only-props': ESLintRule;
};

Usage Examples:

// ✓ Good - Specific PropTypes instead of generic ones
MyComponent.propTypes = {
  user: PropTypes.shape({
    id: PropTypes.number.isRequired,
    name: PropTypes.string.isRequired,
    email: PropTypes.string
  }),
  items: PropTypes.arrayOf(PropTypes.string),
  config: PropTypes.objectOf(PropTypes.string)
};

// ✗ Bad - Generic PropTypes (when forbidden)
MyComponent.propTypes = {
  user: PropTypes.object,    // Too generic
  items: PropTypes.array,    // Too generic
  data: PropTypes.any        // Too generic
};

// ✓ Good - Primitive default props
MyComponent.defaultProps = {
  count: 0,
  title: 'Default Title',
  isVisible: false
};

// ✗ Bad - Object/array as default prop (creates new instance each time)
MyComponent.defaultProps = {
  items: [],        // New array each render
  config: {},       // New object each render
  user: { name: '' } // New object each render
};

// ✓ Good - Using exact prop types (Flow/TypeScript)
type Props = {|
  name: string,
  age: number
|};

// ✓ Good - Read-only props (TypeScript)
type Props = {
  readonly name: string;
  readonly age: number;
};

Component Props Interface

Rules for component prop interface definition and validation.

const propsInterfaceRules = {
  /** Forbid component props */
  'react/forbid-component-props': ESLintRule;
  /** Forbid DOM props */
  'react/forbid-dom-props': ESLintRule;
  /** Prevent passing of children as props */
  'react/no-children-prop': ESLintRule;
};

Usage Examples:

// ✓ Good - Using children prop correctly
const Container = ({ children, className }) => (
  <div className={className}>
    {children}
  </div>
);

<Container className="wrapper">
  <p>Child content</p>
</Container>

// ✗ Bad - Passing children as prop
<Container children={<p>Child content</p>} />

// ✓ Good - Allowed component props
<MyComponent 
  title="Hello"
  onAction={handleAction}
  data={items}
/>

// ✗ Bad - Forbidden component props (when configured)
<MyComponent 
  style={{ color: 'red' }}  // Forbidden if style is restricted
  className="my-class"      // Forbidden if className is restricted
/>

// Configuration example:
{
  "rules": {
    "react/forbid-component-props": ["error", {
      "forbid": ["style", "className"]
    }],
    "react/forbid-dom-props": ["error", {
      "forbid": ["id", "style"]
    }]
  }
}

PropTypes with Higher-Order Components

Rules for handling PropTypes in HOCs and component composition.

const hocPropTypesRules = {
  /** Handle propTypes in HOCs correctly */
  'react/forbid-foreign-prop-types': ESLintRule;
};

Usage Examples:

// ✓ Good - HOC that properly handles PropTypes
const withAuth = (WrappedComponent) => {
  const AuthenticatedComponent = (props) => {
    if (!isAuthenticated()) {
      return <LoginPrompt />;
    }
    return <WrappedComponent {...props} />;
  };
  
  // Properly copy PropTypes
  AuthenticatedComponent.propTypes = WrappedComponent.propTypes;
  AuthenticatedComponent.displayName = `withAuth(${WrappedComponent.displayName || WrappedComponent.name})`;
  
  return AuthenticatedComponent;
};

// ✗ Bad - Accessing foreign PropTypes directly
const MyComponent = ({ name }) => <div>{name}</div>;

const AnotherComponent = () => {
  // Don't access PropTypes from other components
  const nameType = MyComponent.propTypes.name;
  return <div>Type: {nameType}</div>;
};

Advanced PropTypes Patterns

Advanced PropTypes usage patterns and validations.

const advancedPropTypesRules = {
  /** Custom PropTypes validation */
  customValidators: PropTypesValidators;
};

interface PropTypesValidators {
  /** Custom validator functions */
  (props: any, propName: string, componentName: string): Error | null;
}

Usage Examples:

// ✓ Good - Custom PropTypes validators
const customEmailValidator = (props, propName, componentName) => {
  const value = props[propName];
  if (value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
    return new Error(
      `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected a valid email address.`
    );
  }
  return null;
};

MyComponent.propTypes = {
  email: customEmailValidator,
  age: (props, propName, componentName) => {
    const value = props[propName];
    if (value && (value < 0 || value > 120)) {
      return new Error(
        `Invalid prop \`${propName}\` of value \`${value}\` supplied to \`${componentName}\`, expected age between 0 and 120.`
      );
    }
    return null;
  }
};

// ✓ Good - Complex PropTypes with oneOfType
MyComponent.propTypes = {
  value: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.number,
    PropTypes.instanceOf(Date)
  ]),
  callback: PropTypes.func.isRequired,
  items: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
      name: PropTypes.string.isRequired,
      optional: PropTypes.bool
    })
  )
};

PropTypes with TypeScript

Integration patterns when using PropTypes alongside TypeScript.

// ✓ Good - TypeScript interfaces with PropTypes for runtime validation
interface UserProps {
  name: string;
  age: number;
  email?: string;
  isActive?: boolean;
}

const User: React.FC<UserProps> = ({ name, age, email = '', isActive = false }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>Age: {age}</p>
      {email && <p>Email: {email}</p>}
      {isActive && <span>Active</span>}
    </div>
  );
};

// Runtime PropTypes validation (optional with TypeScript)
User.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  email: PropTypes.string,
  isActive: PropTypes.bool
};

PropTypes Rule Configuration

PropTypes rules support extensive configuration options:

{
  "rules": {
    "react/prop-types": ["error", {
      "ignore": ["children", "className", "style"],
      "customValidators": ["myCustomValidator"],
      "skipUndeclared": false
    }],
    
    "react/require-default-props": ["error", {
      "forbidDefaultForRequired": true,
      "ignoreFunctionalComponents": false
    }],
    
    "react/forbid-prop-types": ["error", {
      "forbid": ["any", "array", "object"],
      "checkContextTypes": true,
      "checkChildContextTypes": true
    }],
    
    "react/sort-prop-types": ["error", {
      "ignoreCase": true,
      "callbacksLast": false,
      "requiredFirst": false,
      "sortShapeProp": true,
      "noSortAlphabetically": false
    }],
    
    "react/no-unused-prop-types": ["error", {
      "customValidators": ["myCustomValidator"],
      "skipShapeProps": true
    }]
  }
}