Typing Components
Typing Components
Function Component
import React from "react";
// Method 1: React.FC (not recommended)
const greeting: React.FC<{ name: string }> = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
// Method 2: Props type (recommended)
type GreetingProps = {
name: string;
};
function Greeting({ name }: GreetingProps) {
return <h1>Hello, {name}!</h1>;
}
// Method 3: Inline type
function Greeting2({ name }: { name: string }) {
return <h1>Hello, {name}!</h1>;
}
Component with Children
type CardProps = {
title: string;
children: React.ReactNode;
};
function Card({ title, children }: CardProps) {
return (
<div className="card">
<h2>{title}</h2>
<div className="content">{children}</div>
</div>
);
}
// Usage
<Card title="My Card">
<p>This is card content</p>
</Card>
Default Props
type ButtonProps = {
label: string;
variant?: "primary" | "secondary";
size?: "sm" | "md" | "lg";
};
function Button({ label, variant = "primary", size = "md" }: ButtonProps) {
return (
<button className={`btn btn-${variant} btn-${size}`}>
{label}
</button>
);
}
Typing Props
Typing Props
Union Props
type TextProps = {
as: "h1" | "h2" | "h3" | "p";
children: React.ReactNode;
};
function Text({ as: Component, children }: TextProps) {
return <Component>{children}</Component>;
}
// Usage
<Text as="h1">Title</Text>
<Text as="p">Paragraph</Text>
Props with Generics
type ListProps<T> = {
items: T[];
renderItem: (item: T) => React.ReactNode;
};
function List<T>({ items, renderItem }: ListProps<T>) {
return (
<ul>
{items.map((item, index) => (
<li key={index}>{renderItem(item)}</li>
))}
</ul>
);
}
// Usage
<List
items={["apple", "banana", "cherry"]}
renderItem={(item) => item.toUpperCase()}
/>
Extending HTML Props
type CustomInputProps = {
label: string;
error?: string;
} & React.InputHTMLAttributes<HTMLInputElement>;
function CustomInput({ label, error, ...props }: CustomInputProps) {
return (
<div>
<label>{label}</label>
<input {...props} />
{error && <span className="error">{error}</span>}
</div>
);
}
// Usage
<CustomInput
label="Email"
type="email"
placeholder="Enter email"
error="Invalid email"
/>
Typing Hooks
Typing Hooks
useState
// Basic
const [count, setCount] = useState(0); // inferred as number
// Explicit type
const [name, setName] = useState<string>("");
// Complex state
interface User {
id: number;
name: string;
email: string;
}
const [user, setUser] = useState<User | null>(null);
// Union state
type Status = "idle" | "loading" | "error" | "success";
const [status, setStatus] = useState<Status>("idle");
useRef
// DOM reference
const inputRef = useRef<HTMLInputElement>(null);
// Mutable value (not DOM)
const countRef = useRef<number>(0);
// With initial value
const timerRef = useRef<NodeJS.Timeout | null>(null);
useContext
interface AuthContextType {
user: User | null;
login: (email: string, password: string) => Promise<void>;
logout: () => void;
}
const AuthContext = React.createContext<AuthContextType | undefined>(undefined);
function useAuth(): AuthContextType {
const context = useContext(AuthContext);
if (!context) {
throw new Error("useAuth must be used within AuthProvider");
}
return context;
}
useReducer
interface State {
count: number;
}
type Action =
| { type: "increment" }
| { type: "decrement" }
| { type: "reset" };
function reducer(state: State, action: Action): State {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
case "reset":
return { count: 0 };
}
}
const [state, dispatch] = useReducer(reducer, { count: 0 });
Typing Events
Typing Events
React Event Types
// Mouse events
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
console.log(e.clientX, e.clientY);
}
// Keyboard events
function handleKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
console.log(e.key);
}
// Form events
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
// handle submission
}
// Change events
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
Typed Event Handlers
type InputChangeEvent = React.ChangeEvent<HTMLInputElement>;
type FormSubmitEvent = React.FormEvent<HTMLFormElement>;
function SearchForm() {
const [query, setQuery] = useState("");
const handleChange = (e: InputChangeEvent) => {
setQuery(e.target.value);
};
const handleSubmit = (e: FormSubmitEvent) => {
e.preventDefault();
console.log("Searching:", query);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" value={query} onChange={handleChange} />
<button type="submit">Search</button>
</form>
);
}
Generic Event Components
type EventHandler<T> = (event: T) => void;
type ClickableProps = {
onClick: EventHandler<React.MouseEvent<HTMLDivElement>>;
children: React.ReactNode;
};
function Clickable({ onClick, children }: ClickableProps) {
return <div onClick={onClick}>{children}</div>;
}
Practice Problems
Create a reusable React component implementing TypeScript with React. Include proper state management and accessibility.
Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where neededWrite unit and integration tests for TypeScript with React using React Testing Library.
Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility testsOptimize TypeScript with React for performance. Consider memoization, code splitting, and bundle size.
Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysisQuiz
1. How do you type a React component's props?
2. What type represents children in React?
3. How do you type a click event?
4. How do you type useState with complex state?
Flashcards
Question
How do you type a React component?
Click to reveal answer
Answer
function Component({ prop }: PropType) or React.FC<PropType>
Question
What type should you use for children?
Click to reveal answer
Answer
React.ReactNode
Question
How do you type a form event?
Click to reveal answer
Answer
React.FormEvent<HTMLFormElement>
Question
How do you type a DOM ref?
Click to reveal answer
Answer
useRef<HTMLElementType>(null)
Question
What is TypeScript with React?
Click to reveal answer
Answer
TypeScript with React is a key concept in frontend development.
Revision Notes
Key Takeaways
- 1.Function components use props type annotation
- 2.React.ReactNode for children props
- 3.Event handlers use React-specific event types
- 4.useRef needs generic type for DOM elements
- 5.Extend HTML attributes for custom components
Interview Tips
- •Show how to type functional components with props
- •Demonstrate typed event handlers
- •Explain how to type hooks correctly
Cheat Sheet
Cheat Sheet
Component Props
type Props = { name: string; age?: number };
function Comp({ name, age }: Props) { ... }
Children
type Props = { children: React.ReactNode };
Events
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
onSubmit: (e: React.FormEvent<HTMLFormElement>) => void
Hooks
const [val, setVal] = useState<string>("");
const ref = useRef<HTMLInputElement>(null);
const ctx = useContext(MyContext);
Extending HTML Props
type Props = { label: string } & React.InputHTMLAttributes<HTMLInputElement>;