As your MERN Blog grows and other developers (or your future self) start using the components you have built, it becomes valuable to document what props each component expects and what types they should be. PropTypes is React’s built-in runtime type checking system — it validates prop types in development mode and logs a console warning when the wrong type is passed. This lesson covers the complete PropTypes API, how to declare default props cleanly, and when to consider upgrading to TypeScript for compile-time type safety.
Why PropTypes Matter
| Without PropTypes | With PropTypes |
|---|---|
| Wrong prop type causes silent bug | Console warning immediately identifies the problem |
| Other developers must read source to understand the API | PropTypes serve as live documentation |
| Missing required prop discovered at runtime | Missing required prop warned in development |
| API changes silently break call sites | Call sites see warnings when a prop type changes |
PropTypes.object, React will not validate the object’s internal structure. Use PropTypes.shape({}) to validate object props, not just that the prop is an object.Installation and Import
cd client
npm install prop-types
import PropTypes from 'prop-types';
Core PropTypes Validators
import PropTypes from 'prop-types';
function PostCard({ post, featured, onDelete, variant }) {
return <article><h2>{post.title}</h2></article>;
}
PostCard.propTypes = {
// Primitive types
featured: PropTypes.bool,
viewCount: PropTypes.number,
title: PropTypes.string,
// Required
onDelete: PropTypes.func.isRequired,
// Object with known shape
post: PropTypes.shape({
_id: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
excerpt: PropTypes.string,
viewCount: PropTypes.number,
published: PropTypes.bool,
tags: PropTypes.arrayOf(PropTypes.string),
author: PropTypes.shape({
_id: PropTypes.string,
name: PropTypes.string.isRequired,
avatar: PropTypes.string,
}),
}).isRequired,
// Enum — one of a fixed set
variant: PropTypes.oneOf(['standard', 'featured', 'compact']),
// Array of a specific type
tags: PropTypes.arrayOf(PropTypes.string),
// Any React-renderable content
children: PropTypes.node,
// One of multiple types
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
};
Default Props — Modern Approach
// Preferred: default values directly in destructuring
function PostCard({
post,
featured = false,
variant = 'standard',
onDelete = () => {},
tags = [],
}) {
// Defaults are self-documenting here in the signature
}
// Classic approach (still valid, may eventually be deprecated for function components)
PostCard.defaultProps = {
featured: false,
variant: 'standard',
onDelete: () => {},
tags: [],
};
PropTypes for MERN Blog Components
Avatar.propTypes = {
src: PropTypes.string,
name: PropTypes.string.isRequired,
size: PropTypes.number,
};
Spinner.propTypes = {
size: PropTypes.oneOf(['small', 'medium', 'large']),
message: PropTypes.string,
};
Badge.propTypes = {
label: PropTypes.string.isRequired,
variant: PropTypes.oneOf(['default', 'tag', 'success', 'warning', 'error']),
};
ErrorMessage.propTypes = {
message: PropTypes.string.isRequired,
onRetry: PropTypes.func,
};
Common Mistakes
Mistake 1 — Using PropTypes.object instead of PropTypes.shape
❌ Wrong — only confirms it is an object, not what is inside:
PostCard.propTypes = { post: PropTypes.object }; // any object passes
✅ Correct — validate the structure:
PostCard.propTypes = {
post: PropTypes.shape({ title: PropTypes.string.isRequired }).isRequired,
};
Mistake 2 — Forgetting .isRequired on essential props
❌ Wrong — no warning when a critical prop is omitted:
PostCard.propTypes = { post: PropTypes.shape({ ... }) }; // optional by default
✅ Correct — add .isRequired:
PostCard.propTypes = { post: PropTypes.shape({ ... }).isRequired }; // ✓
Mistake 3 — Writing PropTypes.propTypes after default export on anonymous function
❌ Wrong — PostCard is not in scope after an anonymous default export:
export default function PostCard({ post }) { ... }
PostCard.propTypes = { ... }; // ReferenceError in some bundler setups
✅ Correct — name the function, add PropTypes, then export:
function PostCard({ post }) { ... }
PostCard.propTypes = { post: PropTypes.shape({...}).isRequired };
export default PostCard; // ✓
Quick Reference
| Validator | Use For |
|---|---|
PropTypes.string |
Text props |
PropTypes.number |
Numeric props |
PropTypes.bool |
Boolean flags |
PropTypes.func |
Callback props |
PropTypes.arrayOf(T) |
Typed array |
PropTypes.shape({}) |
Object with known structure |
PropTypes.oneOf([]) |
Enum |
PropTypes.node |
Any renderable content |
.isRequired |
Prop must be provided |