How to Validate Props with PropTypes in React

Intermediate6 min interview
Skills tested:
Defining PropTypes for a component with required and optional propsUsing PropTypes.shape for nested object validationUsing PropTypes.arrayOf for arrays of a specific typeProviding defaultProps as fallback values for optional propsKnowing that PropTypes are development-only and TypeScript supersedes them in typed projects

Advertisement

🧩 Scenario

PropTypes appear in legacy codebases and as a baseline React knowledge question. Interviewers in TypeScript shops want to know whether you understand the role difference between runtime validation and compile-time types.

Architecture Walkthrough

What PropTypes Do

PropTypes is a runtime validation library that checks props against declared types during development. When a component receives a prop that does not match its declared type (wrong type, missing required prop, wrong shape), React logs a warning to the console. No error is thrown, no build fails, no component refuses to render — it is advisory only. PropTypes run only in development; production builds strip the checks to avoid the runtime cost.

The practical value is catching integration bugs early: a component author documents what their component expects, and when a consumer passes the wrong type, they see an immediate console warning pointing to the violation. Without PropTypes (in a JavaScript project without TypeScript), there is no indication that a prop is wrong until the component renders incorrectly.

PropTypes vs TypeScript

TypeScript interfaces and PropTypes solve the same problem at different layers. TypeScript checks types at compile time: if you pass a wrong prop type in a .tsx file, the build fails or the editor shows an error before you run the code. PropTypes check types at runtime in a running application during development. In a TypeScript project, TypeScript already covers what PropTypes would catch, at an earlier point, with better error messages. This makes PropTypes redundant in TypeScript codebases. PropTypes are appropriate for JavaScript projects and libraries that need to validate props from consumers who may not be using TypeScript.


Key Code Explained

// JavaScript project: PropTypes provide runtime type documentation
import PropTypes from 'prop-types';

function UserCard({ name, age, role, onSelect, tags }) {
  return (
    <div onClick={() => onSelect(name)}>
      <h3>{name}</h3>
      <p>Age: {age}</p>
      {role && <span className="badge">{role}</span>}
      <ul>{tags.map((tag) => <li key={tag}>{tag}</li>)}</ul>
    </div>
  );
}

// Validate each prop
UserCard.propTypes = {
  name: PropTypes.string.isRequired,           // string, required
  age: PropTypes.number.isRequired,            // number, required
  role: PropTypes.oneOf(['admin', 'user', 'moderator']), // optional enum
  onSelect: PropTypes.func.isRequired,         // function, required
  tags: PropTypes.arrayOf(PropTypes.string),   // optional array of strings
};

// Fallback values for optional props
UserCard.defaultProps = {
  role: null,
  tags: [],
};

export default UserCard;


// PropTypes.shape: validate the structure of an object prop
function ProductCard({ product, onAddToCart }) {
  return (
    <div>
      <h3>{product.name}</h3>
      <p>${product.price}</p>
      <p>{product.description}</p>
      <button onClick={() => onAddToCart(product.id)}>Add to cart</button>
    </div>
  );
}

ProductCard.propTypes = {
  product: PropTypes.shape({
    id: PropTypes.string.isRequired,
    name: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired,
    description: PropTypes.string,      // optional inside shape
  }).isRequired,
  onAddToCart: PropTypes.func.isRequired,
};


// TypeScript project: interface replaces PropTypes entirely
// No need for the prop-types package
interface UserCardProps {
  name: string;          // required
  age: number;           // required
  role?: 'admin' | 'user' | 'moderator';  // optional
  onSelect: (name: string) => void;
  tags?: string[];
}

// TypeScript checks types at compile time — no runtime validation needed
function TypedUserCard({ name, age, role, onSelect, tags = [] }: UserCardProps) {
  return (
    <div onClick={() => onSelect(name)}>
      <h3>{name}</h3>
      <p>Age: {age}</p>
      {role && <span className="badge">{role}</span>}
      <ul>{tags.map((tag) => <li key={tag}>{tag}</li>)}</ul>
    </div>
  );
}

PropTypes.shape is strictly better than PropTypes.object when an object prop has a known structure. PropTypes.object only validates that the prop is an object — it does not validate which keys it has or their types. PropTypes.shape validates each key individually, so a missing id or a price passed as a string produces a specific, actionable warning.


Tradeoffs

Validation methodWhen it runsCatches missing propsError message qualityTypeScript projects
PropTypesRuntime (dev only)Yes (.isRequired)Console warningRedundant
TypeScript interfacesCompile timeYesEditor/build errorPreferred
BothBothYesBothRedundant; adds maintenance burden

What Interviewers Actually Check

  • Whether you use .isRequired on required props (not just listing the type)
  • Whether you use PropTypes.shape over PropTypes.object for structured objects
  • Whether you know PropTypes are stripped in production builds
  • Whether you know TypeScript supersedes PropTypes in typed projects
  • Whether you know when PropTypes still have a place (JS projects, published component libraries)

Follow-Up Questions

  1. A published React component library uses TypeScript internally but ships type definitions (.d.ts files). Should it also include PropTypes for JavaScript consumers?
  2. PropTypes produce console warnings, not thrown errors. Is there a way to make PropTypes violations throw errors in development to make them harder to miss?
  3. How does PropTypes.instanceOf work, and when would you use it over PropTypes.shape?
  4. defaultProps is deprecated for function components in React 19. What replaces it?
  5. If you are writing a component in a JavaScript project with no TypeScript, what is the argument for using JSDoc type annotations instead of PropTypes?

Common Candidate Mistakes

  • Listing a prop type without .isRequired — a missing required prop fails silently with no warning
  • Using PropTypes.object instead of PropTypes.shape — loses all structural validation for nested data
  • Thinking PropTypes provide safety in production — they are stripped and do nothing in the production bundle
  • Adding PropTypes in a TypeScript project where the interface already validates everything
  • Not providing defaultProps for optional props — components receive undefined when the prop is omitted, which can cause runtime errors

Interview Readiness Checklist

Before you leave this question, make sure you can answer:

  • Can you define PropTypes for a component with required, optional, and nested object props?
  • Can you explain what happens when a PropTypes violation occurs?
  • Can you explain that PropTypes are development-only?
  • Can you explain why TypeScript supersedes PropTypes in typed codebases?
  • Can you explain when PropTypes still have value?

Summary

PropTypes validate props at runtime during development, logging console warnings when a prop has the wrong type, is missing, or does not match a declared shape. They are stripped from production builds. Use .isRequired on all props that must be present; use PropTypes.shape instead of PropTypes.object for structured object props; use defaultProps to provide fallback values for optional props. In TypeScript projects, interface declarations perform the same validation at compile time with better tooling integration, making PropTypes redundant. PropTypes remain valuable in JavaScript projects and in published component libraries that need to validate props from consumers who may not be using TypeScript.

Related Videos
Watch these videos to learn more about this topic
Frequently Asked Questions

Do PropTypes work in production?

PropTypes checks are stripped in production builds by most bundlers (the prop-types package detects process.env.NODE_ENV and skips validation). They run only in development. This is why TypeScript is preferred for type safety that persists through the full build and deployment pipeline.

Advertisement


Stay Updated

Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.

Advertisement