6.3 טיפוסים בריאקט הרצאה
טיפוסים בריאקט - TypeScript with React¶
כשעובדים עם ריאקט וטייפסקריפט, יש טיפוסים ייחודיים שצריך להכיר. ריאקט מספקת טיפוסים מובנים שעוזרים לנו לכתוב קומפוננטות בטוחות ומתועדות.
טיפוסי Props¶
כבר ראינו את הדרך הבסיסית להגדיר props עם interface:
props אופציונליים¶
interface CardProps {
title: string;
subtitle?: string; // optional - can be string or undefined
maxWidth?: number; // optional with default value
}
function Card({ title, subtitle, maxWidth = 400 }: CardProps) {
return (
<div style={{ maxWidth: `${maxWidth}px` }}>
<h2>{title}</h2>
{subtitle && <p>{subtitle}</p>}
</div>
);
}
union types ב-props¶
interface AlertProps {
message: string;
severity: "info" | "warning" | "error" | "success";
}
function Alert({ message, severity }: AlertProps) {
const colors: Record<string, string> = {
info: "#2196f3",
warning: "#ff9800",
error: "#f44336",
success: "#4caf50",
};
return (
<div style={{ backgroundColor: colors[severity], color: "white", padding: "12px" }}>
{message}
</div>
);
}
// usage
<Alert message="Operation successful" severity="success" />
<Alert message="Something went wrong" severity="error" />
ReactNode - הטיפוס לתוכן שניתן לרנדור¶
React.ReactNode הוא הטיפוס שמתאר כל דבר שריאקט יכולה לרנדר:
// ReactNode includes:
// - string
// - number
// - boolean (renders nothing)
// - null / undefined (renders nothing)
// - JSX elements
// - arrays of the above
interface ContainerProps {
children: React.ReactNode;
}
function Container({ children }: ContainerProps) {
return <div className="container">{children}</div>;
}
// all of these are valid
<Container>Hello</Container> // string
<Container>{42}</Container> // number
<Container><p>Paragraph</p></Container> // JSX element
<Container>{null}</Container> // null - renders nothing
ReactElement לעומת ReactNode¶
React.ReactNode- כל דבר שאפשר לרנדר (כולל string, number, null)React.ReactElement- רק אלמנטי JSX (מגביל יותר)
ברוב המקרים נשתמש ב-ReactNode כי הוא גמיש יותר.
טיפוסי אירועים - Event Types¶
כשמטפלים באירועים בריאקט, כל אירוע מגיע עם טיפוס מתאים:
function Form() {
// click event
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log("clicked at", e.clientX, e.clientY);
};
// change event (input)
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
console.log("value:", e.target.value);
};
// form submit event
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("form submitted");
};
// keyboard event
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
console.log("Enter pressed");
}
};
return (
<form onSubmit={handleSubmit}>
<input
onChange={handleChange}
onKeyDown={handleKeyDown}
/>
<button onClick={handleClick}>Submit</button>
</form>
);
}
טיפוסי אירועים נפוצים¶
| אירוע | טיפוס |
|---|---|
| onClick | React.MouseEvent<HTMLElement> |
| onChange | React.ChangeEvent<HTMLInputElement> |
| onSubmit | React.FormEvent<HTMLFormElement> |
| onKeyDown / onKeyUp | React.KeyboardEvent<HTMLElement> |
| onFocus / onBlur | React.FocusEvent<HTMLElement> |
| onMouseEnter / onMouseLeave | React.MouseEvent<HTMLElement> |
הטיפוס הגנרי (כמו HTMLButtonElement) מציין את סוג האלמנט שעליו האירוע מתרחש. זה נותן גישה מטויפסת ל-properties הספציפיים של האלמנט.
טיפוסי סגנון - CSSProperties¶
כשמעבירים אובייקט style ב-JSX, הטיפוס הוא React.CSSProperties:
interface BoxProps {
style?: React.CSSProperties;
children: React.ReactNode;
}
function Box({ style, children }: BoxProps) {
const defaultStyle: React.CSSProperties = {
padding: "16px",
borderRadius: "8px",
border: "1px solid #ddd",
};
return <div style={{ ...defaultStyle, ...style }}>{children}</div>;
}
// usage - TypeScript will autocomplete and validate CSS properties
<Box style={{ backgroundColor: "lightblue", fontWeight: "bold" }}>
Content
</Box>
// ERROR: 'colour' does not exist in type 'CSSProperties'
<Box style={{ colour: "red" }}>Content</Box>
CSSProperties נותן השלמה אוטומטית לכל מאפייני ה-CSS ותופס שגיאות כתיב.
קומפוננטות גנריות - Generic Components¶
לפעמים רוצים קומפוננטה שעובדת עם כל טיפוס. כאן נכנסים גנריקס:
interface 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 with strings
<List
items={["apple", "banana", "cherry"]}
renderItem={(fruit) => <span>{fruit}</span>}
/>
// usage with objects
interface User {
name: string;
age: number;
}
<List<User>
items={[{ name: "Alice", age: 30 }, { name: "Bob", age: 25 }]}
renderItem={(user) => <span>{user.name} ({user.age})</span>}
/>
בדוגמה הראשונה TS מסיקה ש-T הוא string. בדוגמה השנייה אנחנו מציינים במפורש List<User>.
דוגמה נוספת - Select גנרי¶
interface SelectProps<T> {
options: T[];
getLabel: (option: T) => string;
getValue: (option: T) => string;
onChange: (option: T) => void;
}
function Select<T>({ options, getLabel, getValue, onChange }: SelectProps<T>) {
return (
<select onChange={(e) => {
const selected = options.find(opt => getValue(opt) === e.target.value);
if (selected) onChange(selected);
}}>
{options.map((option) => (
<option key={getValue(option)} value={getValue(option)}>
{getLabel(option)}
</option>
))}
</select>
);
}
// usage
interface Country {
code: string;
name: string;
}
const countries: Country[] = [
{ code: "IL", name: "Israel" },
{ code: "US", name: "United States" },
];
<Select
options={countries}
getLabel={(c) => c.name}
getValue={(c) => c.code}
onChange={(country) => console.log(country.name)}
/>
טיפוסים שימושיים נוספים¶
HTMLAttributes - הרחבת אטריביוטי HTML¶
כשרוצים שקומפוננטה תתמוך בכל אטריביוטי HTML הסטנדרטיים:
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "primary" | "secondary";
}
function Button({ variant = "primary", children, ...rest }: ButtonProps) {
return (
<button className={`btn-${variant}`} {...rest}>
{children}
</button>
);
}
// now supports all HTML button attributes
<Button variant="primary" disabled type="submit" aria-label="Save">
Save
</Button>
סיכום¶
- מגדירים props עם interface, כולל שדות אופציונליים (
?) ו-union types React.ReactNode- הטיפוס לכל דבר שניתן לרנדור (children וכדומה)- לאירועים יש טיפוסים ייעודיים כמו
React.MouseEvent,React.ChangeEvent React.CSSPropertiesמטפס אובייקטי style עם השלמה אוטומטית- קומפוננטות גנריות משתמשות ב-generics כדי לעבוד עם כל טיפוס
- אפשר להרחיב אטריביוטי HTML עם
extends React.HTMLAttributes