
المزيد والمزيد من المشاريع والفرق تستخدم TypeScript. ومع ذلك ، مجرد تطبيق TypeScript والضغط على أكثر من ذلك هو أشياء مختلفة للغاية.
أقدم إليكم قائمة بأفضل الممارسات عالية المستوى لاستخدام TypeScript والتي ستساعدك في الحصول على أقصى استفادة من هذه اللغة.
لا تكذب
أنواع العقد. ماذا يعني هذا؟ عندما تقوم بتنفيذ دالة ، يصبح نوعها وعدًا للمطورين الآخرين (أو لنفسك في المستقبل!) وهذا ، عند استدعائه ، سيعود بنوع معين من القيمة.
في المثال التالي ، يضمن نوع دالة getUser
أنه يقوم بإرجاع كائن له دوما خاصية: name
age
.
interface User { name: string; age: number; } function getUser(id: number): User { }
TypeScript هي لغة مرنة للغاية. لديها العديد من الحلول الوسط المصممة لتسهيل إدخال اللغة. على سبيل المثال ، يسمح لك بتطبيق وظيفة getUser
مثل هذا:
function getUser(id: number): User { return { age: 12 } as User; }
لا تفعل ذلك! هذا خطأ. بإنشاء مثل هذا الرمز ، فإنك تكذب على المطورين الآخرين (الذين سيستخدمون وظيفتك في وظائفهم). إنهم يتوقعون أن الكائن الذي يتم إرجاعه بواسطة getUser
سيكون له دائمًا نوع من حقل name
. لكنه ليس هناك! علاوة على ذلك ، ماذا يحدث عندما يكتب getUser(1).name.toString()
؟ أنت تعرف جيدًا أن ...
هنا ، بالطبع ، الكذبة تبدو واضحة. ومع ذلك ، باستخدام قاعدة رمز كبيرة ، ستجد نفسك غالبًا في المواقف التي تتطابق فيها القيمة التي ترغب في إرجاعها (أو تمريرها) مع النوع المتوقع. يستغرق الأمر وقتًا وجهدًا للعثور على سبب عدم تطابق النوع ، وكنت في عجلة من أمرك ... لذا قررت استخدام نوع الكتابة.
ومع ذلك ، من خلال القيام بذلك ، كنت كسر العقد المقدس . من الأفضل دائمًا قضاء الوقت وفهم سبب عدم مطابقة الأنواع بدلاً من استخدام نوع الكتابة. من المحتمل جدًا أن يكون بعض أخطاء وقت التشغيل مختبئًا أسفل السطح.
لا تكذب. طاعة العقود الخاصة بك.
كن دقيقا
أنواع الوثائق. عند توثيق وظيفة ، ألا تريد نقل أكبر قدر ممكن من المعلومات؟
أي تعليق لوظيفة getUser
تريد أكثر؟ كلما عرفت أن الوظيفة ترجع ، كان ذلك أفضل. على سبيل المثال ، مع العلم أنه بإمكانه إرجاع undefined
، يمكنك كتابة كتلة if
للتحقق مما إذا كان الكائن الذي أرجعت إليه الوظيفة محددًا قبل طلب خصائص هذا الكائن.
بالضبط نفس الشيء مع الأنواع: كلما تم وصف النوع بدقة أكبر ، زادت المعلومات التي ينقلها.
function getUserType(id: number): string { } function getUserType(id: number): 'standard' | 'premium' | 'admin' { }
الإصدار الثاني من وظيفة getUserType
أكثر getUserType
بكثير ، وبالتالي فإن المتصل في وضع أكثر ملاءمة. من الأسهل معالجة القيمة إذا كنت تعرف (العقود ، تذكر؟) أنها ستكون واحدة من الأسطر الثلاثة المحددة ، وليس فقط أي سطر. للبدء بما تعرفه بالتأكيد - لا يمكن أن تكون القيمة عبارة عن سلسلة فارغة.
دعنا نفكر في مثال أكثر واقعية. يصف نوع الحالة حالة المكون الذي يطلب بعض البيانات من الواجهة الخلفية. هل هذا النوع دقيق؟
interface State { isLoading: boolean; data?: string[]; errorMessage?: string; }
يجب على العميل الذي يستخدم هذا النوع التعامل مع مجموعة غير متوقعة من قيم خصائص الحالة. على سبيل المثال ، يكون الموقف مستحيلًا عند errorMessage
خصائص data
و errorMessage
نفس الوقت: يمكن أن ينجح أو يفشل طلب البيانات.
يمكننا أن نجعل النوع أكثر دقة بكثير بمساعدة أنواع الاتحادات التمييزية :
type State = | { status: 'loading' } | { status: 'successful', data: string[] } | { status: 'failed', errorMessage: string };
الآن لدى العميل الذي يستخدم هذا النوع مزيد من المعلومات: لم يعد بحاجة إلى معالجة مجموعات غير صحيحة من الخصائص.
كن دقيقا تمرير أكبر قدر ممكن من المعلومات على أنواعك.
ابدأ بالأنواع
نظرًا لأن الأنواع هي عقد ومستندات في آن واحد ، فهي رائعة في تصميم وظائفك (أو أساليبك).
هناك العديد من المقالات على الإنترنت التي تنصح المبرمجين بالتفكير قبل كتابة التعليمات البرمجية . أشارك بشكل كامل هذا النهج. إن الإغراء بالانتقال مباشرة إلى الكود أمر رائع ، لكن هذا غالبًا ما يؤدي إلى قرارات سيئة. القليل من الوقت الذي تقضيه في التفكير في التنفيذ يؤتي ثماره دائمًا.
أنواع مفيدة للغاية في هذه العملية. التفكير يؤدي إلى إنشاء تواقيع لأنواع الوظائف المتعلقة بحل مشكلتك. وهذا شيء عظيم ، لأنك تركز على ما تقوم به وظائفك ، بدلاً من التفكير في كيفية القيام بها.
React JS لديه مفهوم مكونات الرتبة العليا (HOC). هذه هي الوظائف التي تمدد المكون المحدد بطريقة ما. على سبيل المثال ، يمكنك إنشاء مكون ذو ترتيب withLoadingIndicator
يضيف مؤشر تحميل إلى مكون موجود.
دعنا نكتب توقيع نوع لهذه الوظيفة. تقبل الوظيفة إدخال المكون وتقوم بإرجاع مكون كذلك. لتمثيل مكون ، يمكننا استخدام نوع React ComponentType
.
ComponentType
هو نوع عام يتم تحديده حسب نوع خصائص المكون. withLoadingIndicator
يقبل مكونًا ويعيد مكونًا جديدًا يعرض إما المكون الأصلي أو مؤشر التحميل. يتم اتخاذ القرار بشأن ما سيتم عرضه استنادًا إلى قيمة الخاصية المنطقية الجديدة - isLoading
. وبالتالي ، يحتاج المكون المرتجع إلى نفس الخصائص مثل الأصل ، تتم إضافة خاصية isLoading
الجديدة فقط.
سنضع اللمسات الأخيرة على النوع. يقبل withLoadingIndicator
مكونًا من النوع ComponentType<P>
، حيث تشير P
إلى نوع الخاصية. يعرض withLoadingIndicator
مكونًا ذا خصائص متقدمة من النوع P & { isLoading: boolean }
.
const withLoadingIndicator = <P>(Component: ComponentType<P>) : ComponentType<P & { isLoading: boolean }> => ({ isLoading, ...props }) => { /* ... */ }
في التعامل مع أنواع الوظائف ، اضطررنا إلى التفكير في ما سيكون على مدخلاته وما سيكون على الإخراج. وبعبارة أخرى ، كان علينا تصميم وظيفة . كتابة تنفيذها الآن سهل.
ابدأ بالأنواع. دع الأنواع تجبرك على التصميم أولاً ، وعندها فقط كتابة التطبيق.
خذ الصرامة
الوصايا الثلاث الأولى تتطلب منك إيلاء اهتمام خاص لأنواع. لحسن الحظ ، عند حل هذه المشكلة ، ليس عليك القيام بكل شيء بنفسك - غالبًا ما يخبرك برنامج التحويل البرمجي لـ TypeScript بأنك تكذب أنواعك أو عندما لا تكون دقيقة بما فيه الكفاية.
يمكنك مساعدة المحول البرمجي في القيام بذلك بشكل أفضل من خلال --strict
العلامة --strict
. هذه علامة تعريف --noImplicitAny
كل خيارات التحقق من النوع الصارمة: - لا يوجد --noImplicitAny
، أي - لا يوجد --noImplicitThis
، - --alwaysStrict
، - --strictBindCallApply
، --strictNullChecks
، - --strictFunctionTypes
، - - --strictFunctionTypes
--strictPropertyInitialization
.
ماذا تفعل الأعلام؟ بشكل عام ، يؤدي تضمينها إلى زيادة عدد أخطاء التحويل البرمجي لـ TypeScript. وهذا جيد! المزيد من أخطاء الترجمة - المزيد من المساعدة من المترجم.
دعونا نرى كيف يساعد --strictNullChecks
علامة --strictNullChecks
على اكتشاف خطأ في التعليمات البرمجية.
function getUser(id: number): User { if (id >= 0) { return { name: 'John', age: 12 }; } else { return undefined; } }
يضمن نوع getUser
أن تقوم الدالة دائمًا بإرجاع كائن من النوع User
. ومع ذلك ، انظر إلى التطبيق: يمكن أيضًا إرجاع دالة undefined
!
لحسن الحظ ، يؤدي تمكين علامة --strictNullChecks
إلى حدوث خطأ في --strictNullChecks
:
Type 'undefined' is not assignable to type 'User'.
المحول البرمجي TypeScript يكتشف الباطل. للتخلص من هذا الخطأ ، قل بصدق الحقيقة كاملة:
function getUser(id: number): User | undefined { /* ... */ }
اقبل دقة فحص النوع. دع المترجم يحميك من الأخطاء.
مواكبة
تتطور TypeScript بوتيرة سريعة جدًا. يتم إصدار إصدار جديد كل شهرين. كل إصدار يجلب تحسينات لغوية كبيرة وميزات جديدة.
يحدث غالبًا أن الميزات الجديدة للغة تتيح لك تحديد الأنواع بدقة أكبر والتحقق منها بشكل أكثر دقة.
على سبيل المثال ، في الإصدار 2.0 تم تقديم أنواع الاتحاد المتمايزة (ذكرتها في الوصية كن دقيقًا ).
قدم الإصدار 3.2 علامة المحول البرمجي - --strictBindCallApply
، والذي يتضمن الكتابة الصحيحة bind
، call
apply
الوظائف.
الإصدار 3.4 تحسين استنتاج الكتابة في وظائف الترتيب العالي ، مما جعل من الأسهل استخدام أنواع الدقيق عند كتابة التعليمات البرمجية بأسلوب وظيفي.
موقفي هو أن التعرف على ميزات اللغة المقدمة في الإصدارات الأخيرة من TypeScript يستحق ذلك بالفعل. غالبًا ما يساعدك ذلك على اتباع الوصايا الأربع الأخرى من القائمة.
نقطة انطلاق جيدة هي خريطة طريق TypeScript الرسمية . سيكون من الجيد أيضًا التحقق بانتظام من قسم TypeScript في Microsoft Devblog ، نظرًا لأن جميع إعلانات الإصدار تذهب إلى هناك.
مواكبة مع الميزات الجديدة للغة ، والسماح لهذه المعرفة تعمل من أجلك.
ملخص
أتمنى أن تجد القائمة مفيدة. كما هو الحال دائمًا وفي كل شيء ، يجب ألا يتبع المرء هذه الوصايا على نحو أعمى. لكنني أؤمن إيمانًا راسخًا بأن هذه القواعد ستجعلك مطورًا أفضل لبرنامج TypeScript
سأكون سعيدًا لرؤية أفكارك حول هذا الموضوع في التعليقات.
علاوة
هل أعجبك هذا المقال عن TypeScript؟ أنا متأكد من أنك ستعجبك أيضًا بتنسيق PDF المجاني: أخطاء تطوير TypeScript التي تجعل الشفرة غير آمنة.