TypeScript لـ React، باختصار
يجعل TypeScript تطبيقات React أكثر أمانًا وأسهل في العمل عليها. تحصل على أخطاء واضحة، وإكمال تلقائي رائع، وكود يوثق نفسه. ابدأ صغيرًا، وأضف الأنواع حيث تساعد، وتوسع من هناك.
لماذا يساعد
- اكتشاف الأخطاء قبل وقت التشغيل (على سبيل المثال، "الكائن ربما غير محدد")
- الإكمال التلقائي للدعائم، والحالة، واستجابات API
- إعادة بناء آمنة وواجهات برمجة تطبيقات أوضح
ما يجب كتابة أنواعه أولاً
- دعائم المكونات والأحداث
- استجابات API وحالة النموذج
- الأدوات المساعدة القابلة لإعادة الاستخدام (مع الأنواع العامة)
مثال بسيط
interface ButtonProps { label: string; onClick?: () => void }
export function Button({ label, onClick }: ButtonProps) {
return <button onClick={onClick}>{label}</button>;
}
نصائح عملية
- فضل
interface
للكائنات؛type
للاتحادات/الأسماء المستعارة - تجنب
any
؛ استخدمunknown
أو الأنواع العامة - أعد نتائج مكتوبة من مساعدي API
- لا تفرط في كتابة الأنواع؛ حافظ على قابليتها للقراءة
خلاصة القول
ابدأ بأنواع الدعائم وواجهات برمجة التطبيقات، ثم أضف المزيد حيث يقلل من الأخطاء ويحسن تجربة المطور.
export function useLocalStorage<T>(key: string, initial: T) {
const [value, setValue] = React.useState<T>(() => {
const raw = localStorage.getItem(key);
return raw ? (JSON.parse(raw) as T) : initial;
});
React.useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue] as const;
}
السياق مع المحددات
تجنب إعادة عرض جميع المستهلكين عن طريق كشف خطافات المحدد:
type State = { theme: "light" | "dark"; user?: { id: string; name: string } };
const AppState = React.createContext<State | null>(null);
export function useTheme() {
const ctx = React.useContext(AppState);
if (!ctx) throw new Error("useTheme must be used within provider");
return ctx.theme;
}
أنماط المكونات
- اتحادات مميزة للمكونات ذات المتغيرات الثقيلة
- أنواع قوالب حرفية لأسماء الفئات والرموز
- أنواع الأدوات المساعدة (
Pick
,Omit
,ReturnType
) لتكوين واجهات برمجة التطبيقات
type Variant = "primary" | "secondary" | "ghost";
type Size = "sm" | "md" | "lg";
type ButtonProps = {
variant?: Variant;
size?: Size;
} & React.ButtonHTMLAttributes<HTMLButtonElement>;
export const Button: React.FC<ButtonProps> = ({
variant = "primary",
size = "md",
...rest
}) => {
const cls = `btn ${variant} ${size}` as const;
return <button className={cls} {...rest} />;
};
اختبار الأنواع
استخدم tsd
أو expectTypeOf
لقفل عقود الأنواع في المكتبات. في التطبيقات، فضل الخيارات الصارمة في tsconfig
وأبقِ any
خارج المسارات الساخنة.
الخلاصة
اكتب أنواع السطح العام، واكشف عن خطافات/محددات ضيقة، واستخدم الاتحادات/الأنواع العامة للحفاظ على المكونات معبرة وآمنة.
الأنماط المتقدمة
المكونات متعددة الأشكال
type AsProp<C extends React.ElementType> = {
as?: C;
};
type PolymorphicProps<C extends React.ElementType, P> = AsProp<C> &
Omit<React.ComponentPropsWithoutRef<C>, keyof AsProp<C>> &
P;
export function Text<C extends React.ElementType = "span">({
as,
children,
...rest
}: PolymorphicProps<C, { weight?: "regular" | "bold" }>) {
const Component = (as || "span") as React.ElementType;
return <Component {...rest}>{children}</Component>;
}
فحوصات الشمولية
type Status = "idle" | "loading" | "success" | "error";
function assertNever(x: never): never {
throw new Error(`Unhandled: ${x}`);
}
function statusToColor(s: Status) {
switch (s) {
case "idle":
return "gray";
case "loading":
return "blue";
case "success":
return "green";
case "error":
return "red";
default:
return assertNever(s);
}
}
مساعدات الاستدلال
استخدم satisfies
للحفاظ على التوسيع تحت السيطرة والحفاظ على الأنواع الحرفية.
const routes = {
home: "/",
blog: "/blog",
post: (slug: string) => `/post/${slug}`,
} as const satisfies Record<string, unknown>;