Agent skill
typescript-prop-definition
TypeScript interface conventions for component props with JSDoc comments and utility types. PROACTIVELY activate for: (1) defining component prop interfaces, (2) using generics for reusable components, (3) integrating cva VariantProps. Triggers: "props", "interface", "VariantProps"
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/typescript-prop-definition
SKILL.md
TypeScript Prop Definition
Interface Convention
Use interface for component props:
tsx
/**
* Props for the Button component
*/
interface ButtonProps {
/** Button text or content */
children: React.ReactNode;
/** Click handler */
onClick?: () => void;
/** Whether button is disabled */
disabled?: boolean;
}
export function Button({ children, onClick, disabled }: ButtonProps) {
// ...
}
JSDoc Comments
Document each prop:
tsx
interface UserCardProps {
/** User's full name */
name: string;
/** User's email address */
email: string;
/** Optional avatar URL */
avatarUrl?: string;
/** Callback when card is clicked */
onSelect?: (userId: string) => void;
}
Generics for Reusable Components
tsx
interface ListProps<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
keyExtractor: (item: T) => string;
}
function List<T>({ items, renderItem, keyExtractor }: ListProps<T>) {
return (
<ul>
{items.map(item => (
<li key={keyExtractor(item)}>
{renderItem(item)}
</li>
))}
</ul>
);
}
// Usage
<List
items={users}
renderItem={(user) => <span>{user.name}</span>}
keyExtractor={(user) => user.id}
/>
Utility Types
Extending Native Props
tsx
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'default' | 'destructive';
isLoading?: boolean;
}
export function Button({ variant, isLoading, children, ...props }: ButtonProps) {
return (
<button {...props} disabled={isLoading || props.disabled}>
{isLoading ? 'Loading...' : children}
</button>
);
}
Pick/Omit
tsx
// Pick specific fields from existing type
type UserPublicInfo = Pick<User, 'name' | 'email'>;
// Omit sensitive fields
type UserWithoutPassword = Omit<User, 'password'>;
// Partial - all fields optional
type PartialUser = Partial<User>;
// Required - all fields required
type RequiredUser = Required<PartialUser>;
ComponentPropsWithoutRef
tsx
import { ComponentPropsWithoutRef } from 'react';
interface InputProps extends ComponentPropsWithoutRef<'input'> {
label: string;
error?: string;
}
export function Input({ label, error, ...props }: InputProps) {
return (
<div>
<label>{label}</label>
<input {...props} />
{error && <span className="text-destructive">{error}</span>}
</div>
);
}
cva + VariantProps Pattern
tsx
import { cva, type VariantProps } from 'class-variance-authority';
const buttonVariants = cva("base-classes", {
variants: {
variant: {
default: "...",
destructive: "...",
},
size: {
default: "...",
sm: "...",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
// Automatically inferred type from cva
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {
// variant?: "default" | "destructive" - inferred from cva
// size?: "default" | "sm" - inferred from cva
}
export function Button({ variant, size, className, ...props }: ButtonProps) {
return (
<button
className={buttonVariants({ variant, size, className })}
{...props}
/>
);
}
Polymorphic Components
tsx
type PolymorphicComponentProps<E extends React.ElementType> = {
as?: E;
children: React.ReactNode;
} & Omit<React.ComponentPropsWithoutRef<E>, 'as' | 'children'>;
function Box<E extends React.ElementType = 'div'>({
as,
children,
...props
}: PolymorphicComponentProps<E>) {
const Component = as || 'div';
return <Component {...props}>{children}</Component>;
}
// Usage
<Box>Default div</Box>
<Box as="section">Section element</Box>
<Box as="a" href="/about">Link element</Box>
Anti-Patterns
- Using
anytype - Missing JSDoc comments
- Manually typing variants (use VariantProps)
children: any(useReact.ReactNode)- Not extending native element props
Best Practices
- Explicit interface with JSDoc
- Use VariantProps for cva
- Leverage utility types (Pick, Omit, Partial)
- Extend native HTML attributes when wrapping elements
- Use generics for truly reusable components
Related Skills: typescript-type-safe-api-contracts, shadcn-component-scaffolding
Didn't find tool you were looking for?