Prop Types
Common PropTypes definitions for consistent type checking across React components in the WorkPayCore frontend application.
Modal PropTypes
ModalType
Standard PropType definition for modal components.
Properties:
isOpen(bool, required): Whether the modal is openonClose(func, required): Function to close the modal
Example:
import PropTypes from 'prop-types';
import { ModalType } from '@/utils/propTypes';
const MyModal = ({ modal, children }) => {
return (
<Modal isOpen={modal.isOpen} onClose={modal.onClose}>
{children}
</Modal>
);
};
MyModal.propTypes = {
modal: ModalType.isRequired,
children: PropTypes.node,
};
Use Cases:
- Consistent modal prop validation
- Standardized modal interface
- Documentation through PropTypes
User PropTypes
UserType
Standard PropType definition for user objects.
Properties:
id(string): User identifieremail(string): User email addressusername(string): UsernameprofilePhoto(string): URL to profile photo
Example:
import { UserType } from '@/utils/propTypes';
const UserProfile = ({ user, onEdit }) => {
return (
<div className='user-profile'>
<img src={user.profilePhoto} alt={user.username} />
<h2>{user.username}</h2>
<p>{user.email}</p>
<button onClick={() => onEdit(user.id)}>Edit</button>
</div>
);
};
UserProfile.propTypes = {
user: UserType.isRequired,
onEdit: PropTypes.func.isRequired,
};
Use Cases:
- User component prop validation
- Consistent user object structure
- Type safety in user-related components
Usage Examples
Modal Implementation
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { ModalType } from '@/utils/propTypes';
const useModal = () => {
const [isOpen, setIsOpen] = useState(false);
const modal = {
isOpen,
onClose: () => setIsOpen(false),
};
const openModal = () => setIsOpen(true);
return { modal, openModal };
};
const ConfirmDialog = ({ modal, message, onConfirm }) => {
const handleConfirm = () => {
onConfirm();
modal.onClose();
};
return (
<Modal isOpen={modal.isOpen} onClose={modal.onClose}>
<div className='confirm-dialog'>
<p>{message}</p>
<button onClick={handleConfirm}>Confirm</button>
<button onClick={modal.onClose}>Cancel</button>
</div>
</Modal>
);
};
ConfirmDialog.propTypes = {
modal: ModalType.isRequired,
message: PropTypes.string.isRequired,
onConfirm: PropTypes.func.isRequired,
};
User-Related Components
import { UserType } from '@/utils/propTypes';
const UserCard = ({ user, onClick }) => (
<div className='user-card' onClick={() => onClick(user)}>
<img src={user.profilePhoto} alt={user.username} />
<div>
<h3>{user.username}</h3>
<p>{user.email}</p>
</div>
</div>
);
UserCard.propTypes = {
user: UserType.isRequired,
onClick: PropTypes.func,
};
const UserList = ({ users, onUserSelect }) => (
<div className='user-list'>
{users.map(user => (
<UserCard key={user.id} user={user} onClick={onUserSelect} />
))}
</div>
);
UserList.propTypes = {
users: PropTypes.arrayOf(UserType).isRequired,
onUserSelect: PropTypes.func,
};
Extended PropTypes
// Extending base types for specific use cases
const ExtendedUserType = PropTypes.shape({
...UserType,
role: PropTypes.oneOf(['admin', 'user', 'manager']),
createdAt: PropTypes.string,
lastLogin: PropTypes.string,
});
const AdminUserCard = ({ user, onRoleChange }) => {
return (
<div className='admin-user-card'>
<UserCard user={user} />
<select
value={user.role}
onChange={e => onRoleChange(user.id, e.target.value)}
>
<option value='user'>User</option>
<option value='manager'>Manager</option>
<option value='admin'>Admin</option>
</select>
</div>
);
};
AdminUserCard.propTypes = {
user: ExtendedUserType.isRequired,
onRoleChange: PropTypes.func.isRequired,
};
Complex Modal Types
// More complex modal with additional options
const AdvancedModalType = PropTypes.shape({
...ModalType,
size: PropTypes.oneOf(['small', 'medium', 'large']),
closable: PropTypes.bool,
backdrop: PropTypes.oneOf(['static', 'clickable', 'none']),
});
const AdvancedModal = ({ modal, children }) => (
<Modal
isOpen={modal.isOpen}
onClose={modal.onClose}
size={modal.size || 'medium'}
backdrop={modal.backdrop || 'clickable'}
closable={modal.closable !== false}
>
{children}
</Modal>
);
AdvancedModal.propTypes = {
modal: AdvancedModalType.isRequired,
children: PropTypes.node,
};
Custom PropType Validators
You can extend these base types with custom validators:
const EmailUserType = PropTypes.shape({
...UserType,
email: (props, propName, componentName) => {
const email = props[propName];
if (email && !/\S+@\S+\.\S+/.test(email)) {
return new Error(
`Invalid email '${email}' supplied to '${componentName}'. Expected a valid email address.`,
);
}
},
});
Benefits
Type Safety
- Runtime validation of props
- Clear component interfaces
- Documentation through types
Development Experience
- PropTypes warnings in development
- Self-documenting components
- Consistent prop structures
Maintenance
- Easier refactoring
- Clear component contracts
- Reduced bugs
Best Practices
- Always use PropTypes for component props validation
- Mark required props with
.isRequired - Provide default props where appropriate
- Use shape for objects to validate structure
- Create reusable types for common data structures
Related Utilities
- String Utilities - For string prop validation
- Object & Array Utilities - For complex prop structures
TypeScript Migration
When migrating to TypeScript, these PropTypes can be converted to TypeScript interfaces:
interface ModalProps {
isOpen: boolean;
onClose: () => void;
}
interface UserProps {
id?: string;
email?: string;
username?: string;
profilePhoto?: string;
}
Complete Type Definitions
import PropTypes from 'prop-types';
export const ModalType = PropTypes.shape({
isOpen: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
});
export const UserType = PropTypes.shape({
id: PropTypes.string,
email: PropTypes.string,
username: PropTypes.string,
profilePhoto: PropTypes.string,
});