أفضل الممارسات في برمجة TypeScript
تشرح هذه المقالة أفضل الممارسات في برمجة TypeScript۔
يشرح هذا الدليل أفضل الممارسات العملية للاستفادة من أنواع TypeScript لتقليل الأخطاء وكتابة كود أكثر قابلية للقراءة۔
YouTube Video
أفضل الممارسات في برمجة TypeScript
أعظم فائدة في TypeScript هي 'منع الأخطاء باستخدام الأنواع وتوضيح نية الكود'۔
أفضل الممارسات ليست مجرد قواعد، بل هي مجموعة من المبادئ لكتابة كود آمن وقابل للقراءة وسهل الصيانة۔ فيما يلي، نقدم أفضل الممارسات الشائعة في TypeScript مع أمثلة عملية۔
تجنب استخدام any وامنح الأنواع دائمًا تعريفات ذات معنى
أولاً، دعونا نلقي نظرة على نقطة 'تجنب استخدام any وإعطاء أنواع ذات معنى.'۔
any يعطل تمامًا التحقق من الأنواع، مما يلغي الغرض من استخدام TypeScript۔ بدلاً من استخدام any لجعل الأمور تعمل فقط، من المهم توفير أنواع وصفيّة قدر الإمكان۔
1// Bad
2function parse(data: any) {
3 return data.value;
4}يمكن لهذا الكود قبول أي قيمة، لذلك لا يمكن منع الأخطاء أثناء التشغيل۔
1// Good
2type ParsedData = {
3 value: string;
4};
5
6function parse(data: ParsedData): string {
7 return data.value;
8}من خلال تعريف الأنواع، توضح نية المُدخلات والمخرجات وتحسّن الأمان۔
حدد دائمًا هياكل الكائنات صراحةً باستخدام type أو interface.
بعد ذلك، دعونا نلقي نظرة على نقطة 'تحديد هياكل الكائنات دائماً بشكل صريح باستخدام type أو interface.'۔
إذا استخدمت كائنات بشكل عشوائي، فقد تصبح بنيتها غامضة۔ قم دائمًا باستخراج الأنواع من أجل إعادة الاستخدام وسهولة الصيانة۔
1// Bad
2function createUser(user: { name: string; age: number }) {
3 console.log(user.name);
4}حتى في أجزاء الكود الصغيرة، من المهم تطوير عادة فصل الأنواع.۔
1// Good
2type User = {
3 name: string;
4 age: number;
5};
6
7function createUser(user: User): void {
8 console.log(user.name);
9}من خلال تسمية الأنواع، يصبح فهم قاعدة الكود الكاملة أسهل بكثير۔
استخدم أنواع الاتحاد لتمثيل جميع الحالات الممكنة بدقة.
إذا استخدمت أنواع string أو number الخام في الشروط، فقد تمر قيم غير متوقعة۔ باستخدام أنواع الاتحاد، يمكنك تمثيل الحالات المسموح بها فقط على مستوى النوع.۔
1// Bad
2function setStatus(status: string) {
3 console.log(status);
4}في هذا الكود، لا يمكن اكتشاف السلاسل غير المنطقية أو القيم غير الصحيحة في وقت الترجمة.۔
1// Good
2type Status = "idle" | "loading" | "success" | "error";
3
4function setStatus(status: Status): void {
5 console.log(status);
6}عن طريق استخدام أنواع الاتحاد، يمكنك القضاء على 'الحالات المستحيلة' بشكل موثوق في وقت الترجمة.۔ ونتيجة لذلك، ستتحسن أمان الفروع الشرطية وموثوقية الكود.۔
تعامل بشكل صريح مع null و undefined.
بعد ذلك، دعونا نلقي نظرة على نقطة 'معالجة null و undefined بشكل صريح.'۔
في TypeScript، من المهم التعبير عن احتمال غياب قيمة في النوع۔ إذا تركت الأمور غامضة، فقد تؤدي إلى أخطاء وقت التشغيل۔
1type User = {
2 name: string;
3 email?: string;
4};email قد لا يكون موجودًا، لذا يجب التعامل معه بهذا الافتراض۔
1function printEmail(user: User): void {
2 if (user.email) {
3 console.log(user.email);
4 }
5}تحقق دائمًا من القيم الاختيارية قبل استخدامها۔
استخدم تأكيدات النوع (as) فقط كملاذ أخير.
بعد ذلك، دعونا نلقي نظرة على نقطة 'عدم الإفراط في استخدام تأكيدات الأنواع.'۔
تعمل تأكيدات الأنواع على تجاوز فحص الأنواع في TypeScript مؤقتًا لتصرح: 'أنا أعلم أن هذه القيمة من هذا النوع.'۔ الاستخدام الزائد لها يقلل من أمان الأنواع۔
1// Bad
2const value = input as string;في هذا الكود، حتى إذا لم تكن القيمة الفعلية سلسلة نصية، فلن يحدث خطأ، مما قد يؤدي إلى أخطاء وقت التشغيل.۔ كما هو موضح في الكود التالي، اختر إجراء الفحص بأمان باستخدام واقيات النوع أولاً.۔
1// Good
2function isString(value: unknown): value is string {
3 return typeof value === "string";
4}
5
6if (isString(input)) {
7 console.log(input.toUpperCase());
8}واقيات النوع هي آلية لتحديد النوع بأمان أثناء التحقق من القيمة الفعلية.۔ من خلال إعطاء الأولوية لواقيات النوع على تأكيدات الأنواع، يمكنك منع أخطاء وقت التشغيل بسهولة أكبر.۔
لا تعتمد كثيرًا على استنتاج النوع لنوع القيم المرجعة.
بعد ذلك، دعونا نلقي نظرة على نقطة 'عدم الاعتماد بشكل مفرط على الاستدلال في أنواع القيم المرجعة.'۔
استنتاج الأنواع في TypeScript قوي، لكن من الأكثر أمانًا تحديد نوع القيم المرجعة للدوال العامة صراحةً۔ هذا يقلل من التأثير المحتمل للتغييرات في المستقبل۔
1// Bad
2function sum(a: number, b: number) {
3 return a + b;
4}وضح نيتك بوضوح حتى في الدوال الصغيرة۔
1// Good
2function sum(a: number, b: number): number {
3 return a + b;
4}تحديد نوع القيم المرجعة يزيد من استقرار واجهة برمجة التطبيقات (API) الخاصة بك۔
تعامل مع المدخلات بأمان باستخدام unknown.
بعد ذلك، دعونا نلقي نظرة على نقطة 'قبول المدخلات الخارجية بأمان باستخدام unknown.'۔
بالنسبة للمدخلات الخارجية مثل واجهات برمجة التطبيقات أو JSON أو إدخال المستخدم، استخدم unknown بدلاً من any.۔ من خلال القيام بذلك، تضمن التحقق من جميع القيم، مما يحافظ على أمان الأنواع.۔
1// Bad
2function handleResponse(data: any) {
3 console.log(data.id);
4}إليك كيفية التحقق من الأنواع باستخدام unknown۔
1// Good
2function handleResponse(data: unknown): void {
3 if (
4 typeof data === "object" &&
5 data !== null &&
6 "id" in data
7 ) {
8 console.log((data as { id: number }).id);
9 }
10}لا يمكن استخدام unknown كما هو؛ إنه نوع يتطلب التحقق.۔ يكون ذلك فعالاً بشكل خاص عند التعامل مع المدخلات الخارجية.۔
زد من التعبيرية عن طريق دمج أنواع صغيرة.
بعد ذلك، دعونا نلقي نظرة على نقطة 'زيادة وضوح الأنواع من خلال دمج أنواع صغيرة.'۔
تعريف أنواع كبيرة مرة واحدة يقلل من القابلية للقراءة والصيانة۔ قسم أنواعك إلى وحدات ذات معنى وادمجها حسب الحاجة۔
1type Id = number;
2
3type UserProfile = {
4 id: Id;
5 name: string;
6};
7
8type UserWithStatus = UserProfile & {
9 status: "active" | "inactive";
10};التعامل مع الأنواع كمكونات يساعد في تنظيم التصميم الخاص بك۔
type و interface
مزايا interface
type و interface يمكن أن يحددا الأنواع، لكن استخداماتهما وخصائصهما المقصودة تختلف۔ من خلال استخدامهما للأدوار المناسبة، تصبح نية تعريفات الأنواع الخاصة بك أوضح۔
1// Bad
2type User = {
3 id: number;
4 name: string;
5};
6
7type AdminUser = {
8 id: number;
9 name: string;
10 role: "admin";
11};إذا قمت بتكرار الأجزاء المشتركة بهذه الطريقة، يصبح الكود لديك عرضة للتغييرات۔
1// Good
2interface User {
3 id: number;
4 name: string;
5}
6
7interface AdminUser extends User {
8 role: "admin";
9}interface مثالي للتصاميم التي تتضمن الامتداد (extends) وهو الأنسب للتعبير عن 'شكل' الأشياء۔
مزايا type
من ناحية أخرى، type أكثر تعبيرًا ومناسب لمعالجة أنواع الاتحاد والتقاطع۔
1// Good
2type Status = "idle" | "loading" | "success" | "error";
3
4type ApiResponse<T> =
5 | { status: "success"; data: T }
6 | { status: "error"; message: string };type مناسب للتعبير عن الحالات، الخيارات، والتوليفات۔
إرشادات لاختيار بين type و interface
كقاعدة عامة، استخدم interface لهياكل الكائنات والعقود، وtype عندما تحتاج تعبيرية الاتحاد، التقاطع، أو العمليات على الأنواع۔
كلاهما يعمل بشكل مشابه، ولكن من المهم الاختيار بناءً على ما يوضح سبب وجود النوع۔
تعامل مع الأنواع على أنها توثيق.
وأخيراً، دعونا نلقي نظرة على نقطة 'كتابة الأنواع كوثائق.'۔
تعريفات الأنواع الجيدة تنقل معلومات أكثر مما يمكن أن تفعله التعليقات۔ من المهم أن نهدف إلى حالة يمكن فيها فهم المواصفات بمجرد النظر إلى الأنواع.۔
1type ApiError = {
2 code: number;
3 message: string;
4 retryable: boolean;
5};بهذه الطريقة، واحدة من أقوى مزايا TypeScript هي أن تعريفات الأنواع يمكن أن تعمل كمستند مواصفات.۔
الملخص
أفضل الممارسات في TypeScript ليست حول أن تكون صارمًا بشكل مفرط۔ الجوهر هو توضيح النية من خلال الأنواع وكتابة كود قوي أمام التغييرات۔
من خلال تراكم قواعد صغيرة في التطوير اليومي، يمكنك تحقيق آثار طويلة الأمد مثل 'مراجعات أسهل'، 'أخطاء أقل'، و'فهم أفضل لنفسك في المستقبل وللآخرين.'۔
أولاً، من خلال التفكير في 'كيف يمكنني التعبير عن هذا بالأنواع؟' ستكتب كودًا عالي الجودة على نمط TypeScript۔
يمكنك متابعة المقالة أعلاه باستخدام Visual Studio Code على قناتنا على YouTube.۔ يرجى التحقق من القناة على YouTube أيضًا.۔