<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; TypeScript</title><link>https://academy.hsoub.com/programming/javascript/typescript/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x644;&#x63A;&#x629; TypeScript</description><language>ar</language><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; TypeScript &#x648;&#x627;&#x644;&#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x62A;&#x64A; &#x62A;&#x648;&#x641;&#x631;&#x647;&#x627; &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; React</title><link>https://academy.hsoub.com/programming/javascript/typescript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-typescript-%D9%88%D8%A7%D9%84%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%88%D9%81%D8%B1%D9%87%D8%A7-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-react-r1218/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/6083b394ce5f2_TypeScriptReact.png.4176c2a7e4e8fbfcca8cd10280008d40.png" /></p>

<p>
	علينا أولًا وقبل أن ندخل في موضوع استخدام TypeScript مع React تحديد ما يلزمنا وما الذي نهدف لتحقيقه. فعندما يعمل كل شيء كما ينبغي، ستساعدنا TS في التقاط الأخطاء التالية:
</p>

<ul>
<li>
		محاولة تمرير خاصيات Props زائدة أو غير مطلوبة لمكوِّن
	</li>
	<li>
		نسيان تمرير خاصية يحتاجها المكوَّن
	</li>
	<li>
		تمرير خاصية من النوع الخاطئ إلى مكوِّن
	</li>
</ul>
<p>
	ستساعدنا TS على التقاط أيًا من الأخطاء السابقة ضمن المحرر مباشرة. وفي حال لم نستخدم TS، سنضطر إلى التقاط هذه الأخطاء لاحقًا عن طريق الاختبارات، وربما سنقضي وقتًا مرهقًا في إيجاد مسبباتها.
</p>

<p>
	هذه الأسباب كافية حتى الآن لنبدأ إذًا!
</p>

<h2>
	إنشاء تطبيق React باستخدام TypeScript
</h2>

<p>
	يمكننا استخدام <a data-ss1621337058="1" data-ss1621337687="1" href="https://create-react-app.dev/" rel="external nofollow">create-react-app</a> لإنشاء تطبيق React باستخدام TS بإضافة الوسيط <code>template</code> إلى سكربت التهيئة الأولية. لذا نفّذ الأمر التالي لإنشاء تطبيق create-react-app باستخدام TS:
</p>

<pre class="ipsCode">
npx create-react-app my-app --template typescript
</pre>

<p>
	ينبغي بعد تنفيذ الأمر، أن تحصل على تطبيق React مكتمل يستخدم TS. يمكنك أن تشغل التطبيق باستخدام الأمر <code>npm start</code> في جذر المشروع.
</p>

<p>
	لو ألقينا نظرة على الملفات والمجلدات، ستجد أن التطبيق لا يختلف كثيرًا عن التطبيقات التي تستخدم JavaScript صرفة. إذ تقتصر الاختلافات على تحول الملفات التي تحمل إحدى اللاحقتين js. و jsx. إلى ملفات باللاحقتين ts.وtsx. وستحتوي هذه الملفات على مسجلات للأنواع، كما سيحتوي المجلد الجذري على الملف tsconfig.json.
</p>

<p>
	لنلق نظرة الآن على الملف tsconfig.json الذي أُنشئ نيابة عنا. ينبغي أن تكون قواعد التهيئة ضمنه مناسبة إلى حد ما، إلا أنّ هذه القواعد ستسمح بتصريف ملفات JavaScript، لأن القاعدة <code>allowJs</code> تأخذ القيمة "true". لا بأس بذلك إن كنت ستمزج بين TS و JavaScript (في الحالة التي تعمل فيها مثلًا على تحويل شيفرة JS إلى TS أو ما شابه)، لكننا نريد هنا إنشاء تطبيق TS صرف، لذا سنغير قيمة القاعدة <code>allowJs</code> إلى false.
</p>

<p>
	استخدمنا في المشروع السابق المدقق لمساعدتنا في فرض أسلوب برمجة معين، سنفعل ذلك أيضًا في هذا التطبيق. لا حاجة لتثبيت أية اعتماديات لأن create-react-app قد اهتم بكل الترتيبات.
</p>

<p>
	يحمل الملف ذو اللاحقة "eslintrc." قواعد eslint التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_7" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"env"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"browser"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"es6"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"jest"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">"eslint:recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:react/recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:@typescript-eslint/recommended"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"react"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"@typescript-eslint"</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"settings"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"react"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"pragma"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"React"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"detect"</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@typescript-eslint/explicit-function-return-type"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	طالما أنّ النوع الذي تعيده جميع مكوّنات React هي عناصر JSX أو القيمة null، سنغير قواعد المدقق قليلًا بإلغاء تفعيل القاعدة <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/explicit-function-return-type.md" rel="external nofollow">explicit-function-return-type</a>. وهكذا لن نحتاج إلى التصريح عن نوع القيمة التي تعيدها الدالة في كل مكان.
</p>

<p>
	علينا أيضًا أن نجعل المدقق قادرًا على فهم ملفات "tsx."، وهي المقابل في TS لملفات "jsx." في React. سننفذ ذلك بتغيير السكربت lint في الملف package.json على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_9" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
    </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts start"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"build"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts build"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts test"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eject"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"react-scripts eject"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"lint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint './src/**/*.{ts,tsx}'"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قد تحتاج إلى استخدام علامة التنصيص المزدوجة عند كتابة مسار المدقق:
</p>

<pre class="ipsCode">
{lint": "eslint './src/**/*.{ts,tsx}
</pre>

<p>
	وذلك إن كنت تعمل على نظام Windows.
</p>

<p>
	لو نفذنا الآن الأمر <code>npm run lint</code> سنحصل على رسالة خطأ من المدقق eslint مجددًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67125" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/lint_error_01.png.2a3d92830b7142902a7e38e44bdb1fab.png" rel=""><img alt="lint_error_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67125" data-unique="82yia8abt" src="https://academy.hsoub.com/uploads/monthly_2021_05/lint_error_01.png.2a3d92830b7142902a7e38e44bdb1fab.png"></a>
</p>

<p>
	لماذا يحدث ذلك؟ تخبرنا رسالة الخطأ أنّ الملف serviceWorker.ts لا يتقيد بقواعد المدقق. والسبب في ذلك، أنّ الدالة <code>register</code> ستستخدم دوال أخرى عُرِّفت لاحقًا في الملف نفسه وهذا لا يتوافق مع القاعدة<a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-use-before-define.md" rel="external nofollow">typescript-eslint/no-use-before-define@</a> . ولإصلاح المشكلة لا بدّ من نقل الدالة <code>register</code> إلى آخر الملف.
</p>

<p>
	لا ينبغي أن تظهر أية أخطاء بعد الآن. لا يشكل الخطأ السابق عائقًا في واقع الأمر، لأننا لن نحتاج إلى الملف serviceWorker.ts. لذا من الأفضل حذفه.
</p>

<h2>
	مكونات React مع TypeScript
</h2>

<p>
	لنتأمل المثال التالي لتطبيق React كُتب باستخدام JavaScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_11" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">'react-dom'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pln"> from </span><span class="str">"prop-types"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Welcome</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> props </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="typ">Welcome</span><span class="pun">.</span><span class="pln">propTypes </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropTypes</span><span class="pun">.</span><span class="pln">string
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> element </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Welcome</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Sara"</span><span class="pln"> </span><span class="pun">/&gt;;</span><span class="pln">
</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">element</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"root"</span><span class="pun">));</span></pre>

<p>
	لدينا في هذا المثال المكوًن <code>Welcome</code> الذي نمرر إليه اسمًا كخاصية ليقوم بتصييره على الشاشة.
</p>

<p>
	ينبغي أن يكون الاسم من النوع string وقد استخدمنا الحزمة <a data-ss1621337058="1" data-ss1621337687="1" href="https://www.npmjs.com/package/prop-types" rel="external nofollow">prop-types</a> التي تعرفنا عليها في القسم 5، لكي نحصل على تلميحات حول الأنواع المطلوبة لخصائص المكوّنات وتحذيرات عند استخدام خصائص من النوع الخاطئ.
</p>

<p>
	لن نحتاج إلى الحزمة prop-types أبدًا عند استخدام TS. إذ يمكننا تعريف الأنواع بمساعدة TS، وذلك باستخدام واجهة النوع "FunctionComponent" أو باستخدام اسمها المستعار FC.
</p>

<p>
	عندما نستخدم TS مع المكوّنات، ستبدو مسجلات الأنواع مختلفة قليلًا عن شيفرات TS الأخرى. حيث نضيف النوع إلى المتغيًر الذي يُسند إليه المكوّن بدلًا من الدالة وخصائصها. يدعى النوع الناتج عن "FunctionComponent" بالنوع المُعمَّم <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/generics" rel="external">generic</a>. بحيث يمكن أن نمرر لهذه الواجهة نوعًا كمعامل، ثم تستخدمه على أنه النوع الخاص بها.
</p>

<p>
	تبدو تصريحات <code>React.FC</code> و<code>React.FunctionComponent</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_13" style="">
<span class="pln">type FC</span><span class="pun">&lt;</span><span class="pln">P </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">FunctionComponent</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;;</span><span class="pln">

interface </span><span class="typ">FunctionComponent</span><span class="pun">&lt;</span><span class="pln">P </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="pun">(</span><span class="pln">props</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropsWithChildren</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;,</span><span class="pln"> context</span><span class="pun">?:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">ReactElement</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
  propTypes</span><span class="pun">?:</span><span class="pln"> </span><span class="typ">WeakValidationMap</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;;</span><span class="pln">
  contextTypes</span><span class="pun">?:</span><span class="pln"> </span><span class="typ">ValidationMap</span><span class="pun">&lt;</span><span class="pln">any</span><span class="pun">&gt;;</span><span class="pln">
  defaultProps</span><span class="pun">?:</span><span class="pln"> </span><span class="typ">Partial</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;;</span><span class="pln">
  displayName</span><span class="pun">?:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سترى أولًا أن <code>FC</code> ببساطة هو اسم مستعار لواجهة النوع <code>FunctionComponent</code>، وكلاهما من النوع المعمم الذي يمكن تمييزه بسهولة من قوسي الزاوية "&lt;&gt;" بعد اسم النوع. سترى داخل قوسي الزاوية هذه الشيفرة <code>{}=P</code>. وتعني أنه بالإمكان تمرير نوع كمعامل. سيُعرَف النوع الذي سيُمرَّر بالاسم <code>P</code>، وهو افتراضيًا كائن فارغ {}.
</p>

<p>
	لنلق نظرة على السطر الأول من شيفرة <code>FunctionComponent</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_15" style="">
<span class="pun">(</span><span class="pln">props</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PropsWithChildren</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;,</span><span class="pln"> context</span><span class="pun">?:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">ReactElement</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span></pre>

<p>
	تحمل الخصائص النوع PropsWithChildren، وهو أيضًا نوع معمم يُمرَّر إليه النوع P. يمثل النوع "PropsWithChildren" بدوره تقاطعًا <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D8.AA.D9.82.D8.A7.D8.B7.D8.B9_.28Intersection_Types.29" rel="external">intersection</a> بين النوعين بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_17" style="">
<span class="pln">type </span><span class="typ">PropsWithChildren</span><span class="pun">&lt;</span><span class="pln">P</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> P </span><span class="pun">|</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> children</span><span class="pun">?:</span><span class="pln"> </span><span class="typ">ReactNode</span><span class="pln"> </span><span class="pun">};</span></pre>

<p>
	كل ما نحتاج إليه الآن من هذا الشرح الذي قد يبدو معقدًا بأنه من الممكن تعريف النوع وتمريره إلى واجهة النوع <code>FunctionComponent</code>، حيث ستحمل خصائصها بعد ذلك النوع الذي عرًفناه بالإضافة إلى المكوّنات الأبناء.
</p>

<p>
	لنعد إلى مثالنا ونحاول أن نعرًف نوعًا لخصائص المكوًن <code>Welcome</code> باستخدام TS:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_19" style="">
<span class="pln">interface </span><span class="typ">WelcomeProps</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">Welcome</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">WelcomeProps</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">props</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">props</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> element </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&lt;</span><span class="typ">Welcome</span><span class="pln"> name</span><span class="pun">=</span><span class="str">"Sara"</span><span class="pln"> </span><span class="pun">/&gt;;</span><span class="pln">
</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">element</span><span class="pun">,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"root"</span><span class="pun">));</span></pre>

<p>
	عرًفنا في الشيفرة السابقة واجهة النوع <code>WelcomeProps</code> ومررناها إلى المكوّن <code>Welcome</code> عندما صرّحنا عن نوعه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_21" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Welcome</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">WelcomeProps</span><span class="pun">&gt;;</span></pre>

<p>
	يمكننا كتابة الشيفرة بأسلوب أقصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_23" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">Welcome</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;{</span><span class="pln"> name</span><span class="pun">:</span><span class="pln"> string </span><span class="pun">}&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> name </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln">name</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	سيعرف المحرر الآن أنّ الخاصية من النوع string. لكن المدقق لن يقتنع تمامًا بما فعلنا، وسيعترض بأن الخاصية <code>name</code> غير موجودة عند تقييم الخصائص. ويحدث هذا لأنّ قاعدة المدقق ستتوقع منا أن نعرِّف أنواعًا لجميع الخصائص. فلن يدرك المدقق أننا نستخدم TS في تعريف الأنواع لخصائصنا.
</p>

<p>
	لإصلاح الخلل، لا بدّ من إضافة قاعدة تدقيق جديدة إلى الملف "eslintrc.":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_25" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"react/prop-types"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">  </span><span class="pun">},</span><span class="pln">  
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	التمرين 9.14
</h2>

<h3>
	9.14
</h3>

<p>
	أنشئ تطبيق create-react-app مستخدمًا TS وهيئ المدقق لمشروعك بالطريقة التي تعلمناها.
</p>

<p>
	يشبه هذا التمرين تمرينًا نفَّذناه في القسم 1 من المنهاج لكن باستخدام TS هذه المرة بالإضافة إلى بعض التعديلات. إبدأ بتعديل محتويات الملف "index.tsx" لتصبح على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_27" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> from </span><span class="str">"react"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> from </span><span class="str">"react-dom"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> courseName </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Half Stack application development"</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> courseParts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">,</span><span class="pln">
      exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">,</span><span class="pln">
      exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
      name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">,</span><span class="pln">
      exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">];</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;{</span><span class="pln">courseName</span><span class="pun">}&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">exerciseCount</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">1</span><span class="pun">].</span><span class="pln">exerciseCount</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">exerciseCount</span><span class="pun">}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="typ">Number</span><span class="pln"> of exercises</span><span class="pun">{</span><span class="str">" "</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">courseParts</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">((</span><span class="pln">carry</span><span class="pun">,</span><span class="pln"> part</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> carry </span><span class="pun">+</span><span class="pln"> part</span><span class="pun">.</span><span class="pln">exerciseCount</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)}</span><span class="pln">
      </span><span class="pun">&lt;/</span><span class="pln">p</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;,</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"root"</span><span class="pun">));</span></pre>

<p>
	واحذف الملفات غير الضرورية.
</p>

<p>
	إنّ التطبيق ككل موجود في مكوّن واحد، وهذا ما لا نريده. أعد كتابة الشيفرة لتتوزع على ثلاثة مكوّنات: <code>Header</code> و<code>Content</code> و<code>Total</code>. ابق على جميع البيانات ضمن المكوّن <code>App</code> الذي سيمرر كل البيانات اللازمة لمكوّن كخصائص. واحرص على تعريف نوع لكل خاصية من خصائص المكوُنات.
</p>

<p>
	سيتحمل المكوًن <code>Header</code> مسؤولية تصيير اسم المنهاج، وسيصيّر المكوّن <code>Content</code> أسماء الأقسام المختلفة وعدد التمارين في كل قسم، أما المكوّن <code>Total</code> فسيصيّر مجموع التمارين في كل الأقسام.
</p>

<p>
	سيبدو المكوًن <code>App</code> بالشكل التالي تقريبًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_29" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">App</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// const-declarations</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Header</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">courseName</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Content</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">Total</span><span class="pln"> </span><span class="pun">...</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">)</span><span class="pln">
</span><span class="pun">};</span></pre>

<h2>
	استخدام أدق للأنواع
</h2>

<p>
	يتضمن المثال السابق منهاجًا من ثلاثة أقسام، ويمتلك كل قسم نفس الصفتين <code>name</code> و<code>excerciseCount</code>. لكن ماذا لو احتجنا إلى صفات أخرى، وتطلّب كل قسم صفات مختلفة عن الآخر؟ كيف ستبدو شيفرة التطبيق؟
</p>

<p>
	لنتأمل المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_31" style="">
<span class="kwd">const</span><span class="pln"> courseParts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"This is an awesome course part"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
    groupProjectCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Confusing description"</span><span class="pun">,</span><span class="pln">
    exerciseSubmissionLink</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://fake-exercise-submit.made-up-url.dev"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	أضفنا في الشيفرة السابقة صفات أخرى إلى كل قسم. يمتلك الآن كل قسم الصفتين <code>name</code> و<code>exerciseCount</code>، ويمتلك القسمان الأول والثالث الصفة <code>description</code>، كما يمتلك القسمان الثاني والثالث بعض الصفات الإضافية الخاصة.
</p>

<p>
	لنتخيل أنّ تطبيقنا سيستمر في النمو، وأننا سنضطر إلى تمرير الأقسام المختلفة ضمن الشيفرة. وقد تّضاف أيضًا خصائص أخرى أو أقسام أخرى. كيف سنضمن أن الشيفرة قادرة على التعامل مع كل الأنواع المختلفة للبيانات بشكل صحيح، وأننا لن ننس تصيير أحد أقسام المنهاج على صفحة ما؟ هنا ستظهر فائدة اللغة TS!
</p>

<p>
	لنبدأ بتعريف أنواع لأقسام المنهاج المختلفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_33" style="">
<span class="pln">interface </span><span class="typ">CoursePartOne</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartTwo</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  groupProjectCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartThree</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseSubmissionLink</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستُنشئ الشيفرة التالية نوعًا <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D8.A7.D8.AA.D8.AD.D8.A7.D8.AF_.28Union_Types.29" rel="external">موّحَدًا</a> من كل الأنواع. وبالتالي يمكننا استخدامه من أجل مصفوفتنا التي يُفترض بها أن تقبل أي نوع من الأنواع التي تحملها أقسام المنهاج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_37" style="">
<span class="pln">type </span><span class="typ">CoursePart</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CoursePartOne</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">CoursePartTwo</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">CoursePartThree</span><span class="pun">;</span></pre>

<p>
	يمكننا الأن تحديد نوع المتغيّر <code>Coursepart</code>، وسيحذرنا المحرر تلقائيًا إن استخدمنا النوع الخاطئ لإحدى الصفات، أو استخدمنا صفة زائدة، أو نسينا أن نحدد صفة متوقعة. اختبر ذلك بوضع علامة تعليق قبل أي صفة لأي قسم. وبفضل <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D8.B3.D9.84.D8.A7.D8.B3.D9.84_.D8.A7.D9.84.D9.86.D8.B5.D9.8A.D9.91.D8.A9_.D8.A7.D9.84.D8.AD.D8.B1.D9.81.D9.8A.D9.91.D8.A9_.28String_Literal_Types.29" rel="external">القيمة النصية الحرفية</a> التي تحملها السمة <code>name</code>، يمكن أن تحدد TS أي قسم سيحتاج إلى أية صفات إضافية، حتى لو عرفنا المتغير على أنه من النوع الموّحد.
</p>

<p>
	لم نصل درجة القناعة بتطبيقنا بعد، فلا زال هناك تكرار كثير للأنواع، ونريد أن نتجنب ذلك. لهذا سنبدأ بتعريف الصفات المشتركة بين جميع الأقسام، ثم سنعرِّف نوعًا أساسيًا (Base Type) يحتويها. <a data-ss1621337058="1" data-ss1621337687="1" href="http://www.typescriptlang.org/docs/handbook/interfaces.html#extending-interfaces" rel="external nofollow">سنوسع</a> بعد ذلك النوع الأساسي لإنشاء الأنواع الخاصة بكل قسم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_35" style="">
<span class="pln">interface </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartOne</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartTwo</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">;</span><span class="pln">
  groupProjectCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartThree</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseSubmissionLink</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كيف سنستخدم هذه الأنواع الآن في مكوًناتنا؟
</p>

<p>
	من الطرق المفيدة في استخدام هذه الأنواع هي في عبارة switch case. فعندما تصرُح علنًا عن نوع المتغير أنه من النوع الموّحد أو استدلت TS على ذلك واحتوى كل نوع موجود ضمن النوع الموًحد صفة معينة، يمكن استخدام ذلك كمعرّفات للأنواع. يمكن بعد ذلك استخدام البنية switch case للتنقل بين الصفات وستحدد TS الصفات الموجودة في كل حالة من حالات البنية switch.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67134" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/using_types_in_comp_02.png.8e434c63b3095fd50d5228dd1f71f456.png" rel=""><img alt="using_types_in_comp_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67134" data-unique="x479mdght" src="https://academy.hsoub.com/uploads/monthly_2021_05/using_types_in_comp_02.png.8e434c63b3095fd50d5228dd1f71f456.png"></a>
</p>

<p>
	ستميّز TS في المثال السابق أن المتغير <code>coursePart</code> من النوع <code>CoursePart</code>. ويمكنها عندها أن تستدل أن المتغير <code>part</code> من أحد الأنواع التالية <code>CoursePartOne</code> أو <code>CoursePartTwo</code> أو <code>CoursePartThree</code>. أما الصفة <code>name</code> فهي مختلفة ومميزة لكل نوع، لذلك من الممكن استخدامها لتمييز الأنواع وستكون TS قادرة على تحديد الصفات الموجودة في كل حالة case من حالات البنية switch case. وهكذا ستعطي خطأً إن حاولت على سبيل المثال أن تستخدم الصفة <code>part.description</code>ضمن كتلة الحالة Using props to pass data.
</p>

<p>
	كيف سنضيف نوعًا جديدًا؟ من الجيد أن نعرف إن كنا قد أنجزنا مسبقًا آليةً للتعامل مع هذا النوع في شيفرتنا، عند إضافة قسم جديد للمنهاج. فإضافة أي نوع جديد في المثال السابق ستجعله موجودًا في الكتلة default من البنية switch case وبالتالي لن يطبع شيء عن هذا النوع. وقد يكون هذا الأمر مقبولًا في بعض الحالات، كالحالة التي نريد فيها التعامل مع نوع واحد محدد من النوع الموّحد، لكن في أغلب الحالات عليك التعامل مع كل الحالات وبشكل منفصل.
</p>

<p>
	يمكن في TS أن نستخدم طريقة تدعى "التحقق الشامل من الأنواع". ومبدأ هذه الطريقة: أنه في حال واجهتنا قيمة غير معروفة النوع، نستدعي دالة تقبل قيمة من النوع <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/basic_types#.D8.A7.D9.84.D9.86.D9.88.D8.B9_Never" rel="external">never</a> وتعيد قيمة من النوع نفسه.
</p>

<p>
	تمثل الشيفرة التالية تطبيقًا مباشرًا لهذا المبدأ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_39" style="">
<span class="com">/**
 * Helper function for exhaustive type checking
 */</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> assertNever </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">value</span><span class="pun">:</span><span class="pln"> never</span><span class="pun">):</span><span class="pln"> never </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="pln">
    </span><span class="pun">`</span><span class="typ">Unhandled</span><span class="pln"> discriminated </span><span class="kwd">union</span><span class="pln"> member</span><span class="pun">:</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">(</span><span class="pln">value</span><span class="pun">)}`</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لكن لو أردنا استبدال محتويات الكتلة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_41" style="">
<span class="kwd">default</span><span class="pun">:</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> assertNever</span><span class="pun">(</span><span class="pln">part</span><span class="pun">);</span></pre>

<p>
	ووضع علامة تعليق قبل الكتلة Deeper type usage case block سنرى الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67133" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/type_never_helper_error_03.png.a0e0d2eacfa600fa15f02159c70e7700.png" rel=""><img alt="type_never_helper_error_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67133" data-unique="imp5yg9tk" src="https://academy.hsoub.com/uploads/monthly_2021_05/type_never_helper_error_03.png.a0e0d2eacfa600fa15f02159c70e7700.png"></a>
</p>

<p>
	تنص الرسالة أن معاملًا من النوع CoursePartThree لم يُسند إلى معامل من النوع never. أي أننا نستخدم متغيرًا في مكان ما يفترض به أن يكون من النوع never. وهذا ما يدلنا على وجود مشكلة. لكن بمجرد أن نزيل علامة التعليق التي وضعناها على الكتلة Deeper type usage case block سيختفي الخطأ.
</p>

<h2>
	التمرين 9.15
</h2>

<h3>
	9.15
</h3>

<p>
	أضف في البداية النوع information إلى الملف index.tsx واستبدل المتغير <code>courseParts</code> بالمتغير الموجود في المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_43" style="">
<span class="com">// new types</span><span class="pln">
interface </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartOne</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartTwo</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">;</span><span class="pln">
  groupProjectCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">CoursePartThree</span><span class="pln"> extends </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseSubmissionLink</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

type </span><span class="typ">CoursePart</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">CoursePartOne</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">CoursePartTwo</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="typ">CoursePartThree</span><span class="pun">;</span><span class="pln">

</span><span class="com">// this is the new coursePart variable</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> courseParts</span><span class="pun">:</span><span class="pln"> </span><span class="typ">CoursePart</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Fundamentals"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"This is an awesome course part"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Using props to pass data"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
    groupProjectCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    name</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Deeper type usage"</span><span class="pun">,</span><span class="pln">
    exerciseCount</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln">
    description</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Confusing description"</span><span class="pun">,</span><span class="pln">
    exerciseSubmissionLink</span><span class="pun">:</span><span class="pln"> </span><span class="str">"https://fake-exercise-submit.made-up-url.dev"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	نعلم الآن أن واجهتي النوع <code>CoursePartThree</code> و<code>CoursePartOne</code> يتقاسمان صفة تدعى description بالإضافة إلى الصفات الأساسية (الموجودة في واجهة النوع الأساسية)، وهذه الصفة من النوع string في كلتا الواجهتين.
</p>

<p>
	تقتضي مهمتك الأولى أن تصرِّح عن واجهة نوع جديد تتضمن الصفة description وتوسِّع واجهة النوع CoursePartThree. عدّل الشيفرة بعد ذلك بحيث تصبح قادرًا على إزالة الصفة description من الواجهتين دون حدوث أية أخطاء.
</p>

<p>
	أنشئ بعد ذلك المكوّن <code>Part</code> الذي يصيّر كل الصفات من كل نوع ضمن أقسام المنهاج. استخدم آلية تحقق شاملة من الأنواع معتمدًا على بنية switch case. استخدم المكوِّن الجديد ضمن المكوّن <code>Content</code>.
</p>

<p>
	أضف في النهاية واجهة نوع لقسم جديد يحوي على الأقل الصفات التالية: <code>name</code> و<code>exerciseCount</code> و<code>description</code>. ثم أضف واجهة النوع هذه إلى النوع الموّحد <code>CoursePart</code> وأضف البيانات المتعلقة بالقسم إلى المتغير <code>CourseParts</code>. إن لم تكن قد عدّلت المكوّن <code>Content</code> بشكل صحيح، ستحصل على رسالة خطأ، لأنك لم تضف ما يدعم النوع الخاص بالقسم الرابع. أجر التعديلات المناسبة على المكوّن <code>Content</code> لكي تُصيّر كل صفات القسم الجديد دون أخطاء.
</p>

<h2>
	ملاحظة حول تعريف أنواع للكائنات
</h2>

<p>
	لقد استخدمنا <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/interfaces" rel="external">واجهات النوع</a> لتعريف أنواع للكائنات مثل <code>DiaryEntry</code> من الفقرة السابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_45" style="">
<span class="pln">interface </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  weather</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">;</span><span class="pln">
  visibility</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">;</span><span class="pln">
  comment</span><span class="pun">?:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

<p>
	و<code>CoursePart</code> من هذه الفقرة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_47" style="">
<span class="pln">interface </span><span class="typ">CoursePartBase</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  exerciseCount</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد كان بمقدورنا تنفيذ ذلك باستخدام نوع بديل <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A3.D8.B3.D9.85.D8.A7.D8.A1_.D8.A7.D9.84.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D8.A8.D8.AF.D9.8A.D9.84.D8.A9_.28Type_Aliases.29" rel="external">type alias</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_49" style="">
<span class="pln">type </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  weather</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">;</span><span class="pln">
  visibility</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">;</span><span class="pln">
  comment</span><span class="pun">?:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

<p>
	يمكنك استخدام الأسلوبين Interface وType لإنشاء نوع في معظم الحالات. لكن هنالك بعض النقاط التي ينبغي الانتباه لها. فلو عرَّفت عدة واجهات نوع لها نفس الاسم ستحصل على واجهة نوع مختلطة، بينما لو عرّفت عدة أنواع لها الاسم ذاته ستحصل على رسالة خطأ مفادها أنّ نوعًا يحمل نفس الاسم قد جرى التصريح عنه مسبقًا.
</p>

<p>
	<a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A7.D9.84.D9.88.D8.A7.D8.AC.D9.87.D8.A7.D8.AA.D9.8F_.D9.85.D9.8F.D9.82.D8.A7.D8.A8.D9.84.D9.8E_.D8.A3.D8.B3.D9.85.D8.A7.D8.A1.D9.90_.D8.A7.D9.84.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D8.A8.D8.AF.D9.8A.D9.84.D8.A9" rel="external">ينصحك توثيق TS باستخدام الواجهات</a> في معظم الحالات.
</p>

<h2>
	العمل مع شيفرة جاهزة
</h2>

<p>
	من الأفضل عندما تبدأ العمل على شيفرة جاهزة للمرة الأولى أن تلقي نظرة شاملة على هيكلية المشروع وأسلوب العمل. يمكنك البدء بقراءة الملف README.md الموجود في جذر المستودع. يحتوي هذا الملف عادة على وصف موجز للتطبيق ومتطلباته، وكيف سنجعله يعمل لبدء عملية التطوير. إن لم يكن الملف README متاحًا أو أنّ أحدهم فضّل اختصار الوقت ووضعه كمرجع احتياطي، سيكون من الجيد الاطلاع على الملف package.json. ومن الجيد دائمًا تشغيل التطبيق وتجريبه والتحقق من وظائفه.
</p>

<p>
	يمكنك أيضًا تصفح هيكيلة مجلد المشروع لتطلع على وظائفه أو/والمعمارية المستخدمة. لكن هذا الأسلوب لن يفيدك دائمًا، فلربما اختار المطوّر أسلوبًا لم تعهده. ركّزنا في تنظيم <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/fullstack-hy2020/patientor" rel="external nofollow">المشروع التدريبي</a> الذي سنستخدمه في ما تبقى من هذا القسم على الميزات التي يقدمها. حيث يمكنك الاطلاع على الصفحات التي يعرضها التطبيق، وبعض المكوّنات العامة كالوحدات وحالة التطبيق، وتذكر أن للميزات مجالات مختلفة. فالوحدات هي مكونات مرئية على مستوى واجهة المستخدم بينما تحافظ حالة التطبيق على جميع البيانات تحت الستار لكي تستخدمها بقية المكوّنات.
</p>

<p>
	تزوّدك TS بالأنواع التي تخبرك عن شكل بنى البيانات والدوال والمكوّنات والحالة التي ستحصل عليها. يمكنك إلقاء نظرة على الملف types.ts أو أي ملف مشابه كبداية. كما سيساعدك VSCode كثيرًا فمجرد توضيحه للمتغيرات والمعاملات سيمنحك رؤية أفضل للشيفرة. ويعتمد هذا كله بالطبع على طريقة استخدام الأنواع في هذا المشروع.
</p>

<p>
	إن احتوى المشروع اختبارات أجزاء أو اختبارت تكامل فسيكون الاطلاع عليها مفيدًا بالتأكيد. فالاختبارات أداة مفيدة جدًا عندما تعيد كتابة الشيفرة أو عند كتابة ميزات جديدة للتطبيق. وتأكد من عدم تخريب أية ميزة موجودة عندما تبدأ بالتلاعب بالشيفرة. سترشدك TS أيضًا بما يتعلق بالمعاملات والقيم المعادة عندما تتغير الشيفرة.
</p>

<p>
	إن قراءة الشيفرة مهارة بحد ذاتها. لا تقلق إن لم تستطع فهم الشيفرة في البداية، فقد تحتوي الشيفرات على بعض الحالات غير الواضحة أو قد تحتوي أجزاءً أضيفت هنا وهناك خلال عملية التطوير. فلا يمكننا تصور المشاكل التي عانى منها المطوّر السابق لهذه الشيفرة. ويتطلب فهم تفاصيل الشيفرة بشكل كامل الغوص إلى أعماقها وفهم متطلبات المجال الذي تعمل عليه. فكلما قرأت شيفرات أكثر ستصبح أفضل في فهمها واستخدامها. إقرأ شيفرات أكثر مما تكتبه.
</p>

<h2>
	الواجهة الأمامية لتطبيق إدارة المرضى
</h2>

<p>
	لقد حان الوقت لإكمال الواجهة الأمامية للواجهة الخلفية التي بنيناها في التمارين السابقة وقبل أن نتعمق في كتابة الشيفرة، سنشغل الواجهتين معًا.
</p>

<p>
	إن سار كل شيء على ما يرام، سترى صفحة ويب تضم قائمة بالمرضى. تحضر الصفحة قائمة المرضى من الواجهة الخلفية وتصيّرها على الشاشة ضمن جدول بسيط. ستجد أيضًا زرًا لإضافة مريض جديد إلى الواجهة الخلفية. وطالما أننا نستخدم بيانات وهمية بدلًا من قواعد البيانات، فلن تخزّن البيانات التي أضفناها عند إغلاق الواجهة الخلفية. وطبعًا تقييم تصميم واجهة المستخدم UI ليس في صالح المصمم، لذلك سنهمل موضوع واجهة المستخدم حاليًا.
</p>

<p>
	بعد التأكد من كل الأمور، يمكننا الشروع في دراسة الشيفرة. سنجد معظم النقاط المهمة في المجلد /‎src. ولمساعدتك هنالك أيضًا ملف جاهز يصف الأنواع الرئيسية التي يستخدمها التطبيق، والتي علينا ان نوسِّعها أو نعيد كتابتها خلال التمارين.
</p>

<p>
	يمكننا من حيث المبدأ استخدام الأنواع نفسها في الواجهتين الأمامية والخلفية، لكن الواجهة الأمامية ستحتوي على بنى بيانات مختلفة وستستخدمها في حالات مختلفة، مما يجعل الأنواع ضمنها مختلفة. فللواجهة الأمامية على سبيل المثال حالة للتطبيق، ولربما أردت تخزين البيانات ضمن كائنات، بينما تستخدم الواجهة الخلفية مصفوفة. وقد لا تحتاج الواجهة الأمامية إلى كل حقول كائن البيانات المخزّن في الواجهة الخلفية، كما قد تضيف حقولًا جديدة لاستخدامها في التصيير.
</p>

<p>
	ستبدو هيكلية المجلد على النحو التالي
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67132" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/src_folder_strucure_04.png.08ae387a113e9ce7318a44c48a57b12e.png" rel=""><img alt="src_folder_strucure_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67132" data-unique="tttuoktk3" src="https://academy.hsoub.com/uploads/monthly_2021_05/src_folder_strucure_04.png.08ae387a113e9ce7318a44c48a57b12e.png"></a>
</p>

<p>
	تحتوي الواجهة الخلفية حاليًا مكوّنين هما: <code>AddPatientModal</code> و<code>PatientListPage</code>. يحتوي المجلد state على الشيفرة التي تتعامل مع حالة الواجهة الأمامية. وتقتصر وظيفة الشيفرة في هذا المجلد على إبقاء البيانات في مكان واحد وتزويد الواجهة بأفعال بسيطة لتبديل حالة التطبيق.
</p>

<h2>
	التعامل مع حالة التطبيق
</h2>

<p>
	لندرس الطرق المتبعة في التعامل مع حالة التطبيق. إذ يبدو أنّ الكثير من الأشياء تجري خلف الستار، وهي مختلفة قليلًا عن الطرق التي استخدمت سابقًا في المنهاج.
</p>

<p>
	بُني أسلوب إدارة الحالة باستخدام الخطافين <a data-ss1621337058="1" data-ss1621337687="1" href="https://reactjs.org/docs/hooks-reference.html#usecontext" rel="external nofollow">useContext</a> و<a data-ss1621337058="1" data-ss1621337687="1" href="https://reactjs.org/docs/hooks-reference.html#usereducer" rel="external nofollow">useReducer</a> للمكتبة React. وهذا قرار صائب لأنّ التطبيق صغير نوعًا ما ولن نحتاج إلى Redux أو إلى أية مكتبات أخرى لإدارة الحالة. ستجد على الانترنت <a data-ss1621337058="1" data-ss1621337687="1" href="https://medium.com/@seantheurgel/react-hooks-as-state-management-usecontext-useeffect-usereducer-a75472a862fe" rel="external nofollow">مواد تعليمة</a> مفيدة عن استخدام هذه المقاربة.
</p>

<p>
	تستخدم هذه المقاربة أيضًا الواجهة البرمجية <a data-ss1621337058="1" data-ss1621337687="1" href="http://wiki.hsoub.com/React/context" rel="external">context</a> العائدة للمكتبة React، إذ ينص توثيق الواجهة أنها:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		مصممة لمشاركة البيانات التي يمكن اعتبارها بيانات "عامة" لشجرة من مكوّنات React مثل بيانات المستخدم الذي سجل دخوله حاليًا والسمات واللغة المفضلة.
	</p>
</blockquote>

<p>
	فالبيانات المشتركة في حالتنا هي حالة التطبيق ودالة الإيفاد التي تستخدم لإجراء التعديلات على البيانات. ستعمل شيفرتنا بأسلوب يشابه كثيرًا أسلوب Redux في إدارة الحالة والذي خبرناه في القسم 6، لكنها شيفرة أسرع لأنها لا تحتاج أية مكتبات خارجية. يفترض هذا القسم أنك مطلع على طريقة عمل Redux على الأقل، وبعبارة أخرى من المفترض أنك اطلعت على الفصل الأول من القسم 6.
</p>

<p>
	تتضمن الواجهة البرمجية <a data-ss1621337058="1" data-ss1621337687="1" href="http://wiki.hsoub.com/React/context" rel="external">context</a> قناة تضم حالة التطبيق ودالة إيفاد لتغيير الحالة. وقد حُدِّد نوع للحالة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_51" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">State</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  patients</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">[</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">]:</span><span class="pln"> </span><span class="typ">Patient</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	فالحالة كما تُظهر الشيفرة هي كائن بمفتاح واحد يدعى <code>Patients</code> يمتلك <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/TypeScript/advanced_types#.D8.A3.D9.86.D9.88.D8.A7.D8.B9_.D8.A7.D9.84.D9.81.D9.87.D8.B1.D8.B3_.28Index_types.29_.D9.88.D8.AA.D9.88.D9.82.D9.8A.D8.B9.D8.A7.D8.AA_.D8.A7.D9.84.D9.81.D9.87.D8.A7.D8.B1.D8.B3_.D8.A7.D9.84.D9.86.D8.B5.D9.8A.D9.91.D8.A9_.28string_index_signatures.29" rel="external">قاموسًا</a>، أو بعبارة أخرى، يقبل كائنًا له مفاتيح من النوع "string" مع كائن <code>Patient</code> كقيمة له. يمكن لقرينة الفهرسة أن تكون من أحد النوعين "string" أو"number" إذ يمكننا الوصول إلى قيم الكائن باستخدام هذين النوعين. وبهذا نجبر الحالة أن تتقيد بالصيغة التي نريد، وتمنع المطورين من استخدامها بشكل غير صحيح.
</p>

<p>
	لكن انتبه إلى نقطة مهمة! عندما يُصرّح عن نوع بالطريقة التي اتبعناها مع <code>patients</code>، فلن تمتلك TS أية طريقة لمعرفة إن كان المفتاح الذي تحاول الوصول إليه موجودًا أم لا. فلو حاولنا الوصول إلى بيانات مريض بمعرِّف غير موجود، سيعتقد المصرّف أن القيمة المعادة من النوع Patient، ولن تلق أية أخطاء عند محاولة الوصول إلى خصائص هذا الكائن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_53" style="">
<span class="kwd">const</span><span class="pln"> myPatient </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">patients</span><span class="pun">[</span><span class="str">'non-existing-id'</span><span class="pun">];</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myPatient</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لا أخطاء إذ يعتقد المصرّف أن القيمة المعادة </span><span class="pln">
</span><span class="com">//patient من النوع</span></pre>

<p>
	لإصلاح الخلل، يمكننا أن نعرّف نوع القيم التي تحمل بيانات المريض على أنها من نوعٍ موحّد بين <code>Patient</code> و<code>undefined</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_55" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">State</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  patients</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">[</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">]:</span><span class="pln"> </span><span class="typ">Patient</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	وجراء هذا الحل، سيحذرنا المصرّف بالرسالة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_57" style="">
<span class="kwd">const</span><span class="pln"> myPatient </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">patients</span><span class="pun">[</span><span class="str">'non-existing-id'</span><span class="pun">];</span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myPatient</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// error, Object is possibly 'undefined'</span></pre>

<p>
	من الجيد دائمًا إنشاء هذا النوع مع بعض الإضافات الأمنية عندما تستخدم مثلًا بيانات من مصادر خارجية أو قيمة أدخلها المستخدم للوصول إلى بيانات ضمن شيفرتك. لكن إن كنت متأكدًا من أن شيفرتك قادرة على التعامل مع البيانات غير الموجودة، فلا مانع أبدًا من استخدام أول حلٍ قدمناه.
</p>

<p>
	وعلى الرغم من عدم استخدام هذا الأسلوب في هذا القسم، ينبغي الإشارة إلى أن استخدام كائنات <a data-ss1621337058="1" data-ss1621337687="1" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map" rel="external nofollow">Map</a> سيؤمن لك طريقة أكثر تشددًا في استخدام الأنواع. حيث يمكنك أن تُصرح عن نوع لكلٍ من المفتاح ومحتواه. تعيد دالة الوصول <code>()get</code>إلى كائنات Map نوعًا موحّدًا يجمع بين النوع المصرّح عنه و<code>undefined</code>، وبالتالي ستطلب TS تلقائيُا إجراء تحقق من البيانات المستخلصة من كائن Map:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_59" style="">
<span class="pln">interface </span><span class="typ">State</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  patients</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">&lt;</span><span class="pln">string</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Patient</span><span class="pun">&gt;;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> myPatient </span><span class="pun">=</span><span class="pln"> state</span><span class="pun">.</span><span class="pln">patients</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'non-existing-id'</span><span class="pun">);</span><span class="pln"> </span><span class="com">// type for myPatient is now Patient | undefined </span><span class="pln">
console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myPatient</span><span class="pun">.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// error, Object is possibly 'undefined'</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">myPatient</span><span class="pun">?.</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> </span><span class="com">// valid code, but will log 'undefined'</span></pre>

<p>
	تُنفذ التعديلات على الحالة باستخدام دوال الاختزال، تمامًا كما في Redux. عُرِّفت هذه الدوال في الملف reducer.ts بالإضافة إلى النوع Action الذي يبدو على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_61" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">Action</span><span class="pln"> </span><span class="pun">=</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SET_PATIENT_LIST"</span><span class="pun">;</span><span class="pln">
      payload</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Patient</span><span class="pun">[];</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ADD_PATIENT"</span><span class="pun">;</span><span class="pln">
      payload</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Patient</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">};</span></pre>

<p>
	تبدو دالة الاختزال مشابه تمامًا للدوال التي أنشأناها في القسم 6. حيث تغيّر حالة كل نوع من الأفعال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_63" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> reducer </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">state</span><span class="pun">:</span><span class="pln"> </span><span class="typ">State</span><span class="pun">,</span><span class="pln"> action</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Action</span><span class="pun">):</span><span class="pln"> </span><span class="typ">State</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">action</span><span class="pun">.</span><span class="pln">type</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"SET_PATIENT_LIST"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="pun">...</span><span class="pln">state</span><span class="pun">,</span><span class="pln">
        patients</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="pun">...</span><span class="pln">action</span><span class="pun">.</span><span class="pln">payload</span><span class="pun">.</span><span class="pln">reduce</span><span class="pun">(</span><span class="pln">
            </span><span class="pun">(</span><span class="pln">memo</span><span class="pun">,</span><span class="pln"> patient</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> </span><span class="pun">...</span><span class="pln">memo</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[</span><span class="pln">patient</span><span class="pun">.</span><span class="pln">id</span><span class="pun">]:</span><span class="pln"> patient </span><span class="pun">}),</span><span class="pln">
            </span><span class="pun">{}</span><span class="pln">
          </span><span class="pun">),</span><span class="pln">
          </span><span class="pun">...</span><span class="pln">state</span><span class="pun">.</span><span class="pln">patients
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">"ADD_PATIENT"</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="pun">...</span><span class="pln">state</span><span class="pun">,</span><span class="pln">
        patients</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="pun">...</span><span class="pln">state</span><span class="pun">.</span><span class="pln">patients</span><span class="pun">,</span><span class="pln">
          </span><span class="pun">[</span><span class="pln">action</span><span class="pun">.</span><span class="pln">payload</span><span class="pun">.</span><span class="pln">id</span><span class="pun">]:</span><span class="pln"> action</span><span class="pun">.</span><span class="pln">payload
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">};</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> state</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	ينحصر الفرق في أنّ الحالة الآن على شكل قاموس (أو كائن) بدلًا من المصفوفة التي استخدمناها في القسم 6.
</p>

<p>
	تجري الكثير من الأمور في الملف state.ts والتي تهيئ سياق العمل. ويعتبر الخطاف <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/React/hooks_reference#useReducer" rel="external">useReducer</a> الذي يستخدم لإنشاء الحالة، ودالة الإيفاد المكونان الرئيسيان لإنجاز التغييرات على حالة التطبيق، حيث يمرران إلى التابع <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/React/context#.D8.A7.D9.84.D9.85.D8.B2.D9.88.D8.AF_Provider" rel="external">context.povider</a>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_65" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">StateProvider</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">StateProviderProps</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">
  reducer</span><span class="pun">,</span><span class="pln">
  children
</span><span class="pun">}:</span><span class="pln"> </span><span class="typ">StateProviderProps</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> dispatch</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useReducer</span><span class="pun">(</span><span class="pln">reducer</span><span class="pun">,</span><span class="pln"> initialState</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">StateContext</span><span class="pun">.</span><span class="typ">Provider</span><span class="pln"> value</span><span class="pun">={[</span><span class="pln">state</span><span class="pun">,</span><span class="pln"> dispatch</span><span class="pun">]}&gt;</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">children</span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">StateContext</span><span class="pun">.</span><span class="typ">Provider</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يستخدم التابع السابق في تزويد كل المكوّنات بالحالة ودالة الإيفاد، وذلك بفضل الإعدادات الموجودة في الملف index.ts:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_67" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> reducer</span><span class="pun">,</span><span class="pln"> </span><span class="typ">StateProvider</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./state"</span><span class="pun">;</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">StateProvider</span><span class="pln"> reducer</span><span class="pun">={</span><span class="pln">reducer</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">App</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">StateProvider</span><span class="pun">&gt;,</span><span class="pln"> 
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'root'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	كما يُعرّف أيضًا الخطاف <code>useStateValue</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_69" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> useStateValue </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> useContext</span><span class="pun">(</span><span class="typ">StateContext</span><span class="pun">);</span></pre>

<p>
	وتستعمله أيضًا المكوّنات التي تحتاج إلى الحالة أو دالة الإيفاد لتخزينهما:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_71" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useStateValue </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../state"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">PatientListPage</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> patients </span><span class="pun">},</span><span class="pln"> dispatch</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useStateValue</span><span class="pun">();</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا تقلق إن بدا الأمر مربكًا قليلًا، فبالطبع سيبقى كذلك حتى تدرس <a data-ss1621337058="1" data-ss1621337687="1" href="https://wiki.hsoub.com/React/context" rel="external">توثيق context</a> وطريقة استخدامها في <a data-ss1621337058="1" data-ss1621337687="1" href="https://medium.com/@seantheurgel/react-hooks-as-state-management-usecontext-useeffect-usereducer-a75472a862fe" rel="external nofollow">إدارة الحالة</a>. لكن ليس عليك فهم كل ذلك بشكل كامل حتى تحل التمارين.
</p>

<p>
	من الشائع جدًا أن لا تفهم بشكل كامل ما تفعله الشيفرة خلف الستار، عندما تبدأ العمل على مشروع جاهز. فإن كان المشروع مبني بهيكلية جيدة يمكنك أن تثق أن أية تعديلات مدروسة جيدًا لن تؤثر على عمل التطبيق، على الرغم من عدم إدراكك لكامل آليات العمل التي تجري داخله. مع الوقت ستفهم الأجزاء التي لم تكن مألوفة بالنسبة لك، لكن ذلك لن يحدث بين يوم وليلة وخاصة عندما تعمل على مشروع ذو شيفرة ضخمة.
</p>

<h2>
	صفحة قائمة المرضى
</h2>

<p>
	لنتوجه إلى الملف index.ts الموجود في المجلد PateintListPage لنأخذ بعض الأفكار التي تساعدنا على إحضار البيانات من الواجهة الخلفية وتحديث حالة التطبيق. تستخدم الصفحة خطافًا أنشئ خصيصًا لوضع البيانات في الحالة ودالة الإيفاد لتحديث محتوياتها. فعندما ننشئ قائمة بالمرضى لا نحتاج سوى تفكيك خصائص الكائن <code>patients</code> الموجود في حالة التطبيق:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_73" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useStateValue </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../state"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">PatientListPage</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> patients </span><span class="pun">},</span><span class="pln"> dispatch</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useStateValue</span><span class="pun">();</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ونستخدم أيضًا الحالة app التي أنشئت باستخدام الخطاف <code>useState</code> لإدارة حالات إظهار الوحدة أو إخفائها، وكذلك معالجة الأخطاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_75" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">modalOpen</span><span class="pun">,</span><span class="pln"> setModalOpen</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">useState</span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">&gt;(</span><span class="kwd">false</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[</span><span class="pln">error</span><span class="pun">,</span><span class="pln"> setError</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">useState</span><span class="pun">&lt;</span><span class="pln">string </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pun">&gt;();</span></pre>

<p>
	نمرر للخطاف <code>useState</code> نوعًا كمعامل، ثم يُطبَّق على الحالة الفعلية. فالمعامل <code>modalOpen</code> من النوع Boolean والمعامل <code>error</code> من النوع string | undefined. وكلا دالتي الضبط اللتان يعيدهما الخطاف <code>useState</code> سيقبلان معاملات من نوع يماثل النوع الذي يمرر إليها من خلال معامل (يمتلك نوعًا). فالنوع الفعلي للدالة <code>setModalOpen</code> هو ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2347_6" style="">
<span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="typ">React</span><span class="pun">.</span><span class="typ">Dispatch</span><span class="pun">&lt;</span><span class="typ">React</span><span class="pun">.</span><span class="typ">SetStateAction</span><span class="pun">&lt;</span><span class="pln">boolean</span><span class="pun">.</span><span class="pln">
</span></pre>

<p>
	كما نستخدم الدالتين المساعدتين <code>closeModal</code> و<code>openModal</code> لقراءة البيانات بشكل أفضل وأكثر ملاءمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_77" style="">
<span class="kwd">const</span><span class="pln"> openModal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> setModalOpen</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> closeModal </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  setModalOpen</span><span class="pun">(</span><span class="kwd">false</span><span class="pun">);</span><span class="pln">
  setError</span><span class="pun">(</span><span class="kwd">undefined</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	تتعلق الأنواع في الواجهة الأمامية بما قمت بتطويره بإنشائه عند تطوير الواجهة الخلفية في الفصل السابق.
</p>

<p>
	سيحضر المكوّن <code>App</code> عندما يُثبَّت المرضى مستخدمًا المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/axios/axios" rel="external nofollow">axios</a>. ويجدر الانتباه إلى أننا مررنا نوعًا على شكل معامل إلى الدالة <code>axios.get</code> لكي نحدد نوع البيانات التي سنحصل عليها من الاستجابة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_79" style="">
<span class="typ">React</span><span class="pun">.</span><span class="pln">useEffect</span><span class="pun">(()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">&lt;</span><span class="kwd">void</span><span class="pun">&gt;(`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">apiBaseUrl</span><span class="pun">}/</span><span class="pln">ping</span><span class="pun">`);</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> fetchPatientList </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> data</span><span class="pun">:</span><span class="pln"> patients </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">&lt;</span><span class="typ">Patient</span><span class="pun">[]&gt;(</span><span class="pln">
        </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">apiBaseUrl</span><span class="pun">}/</span><span class="pln">patients</span><span class="pun">`</span><span class="pln">
      </span><span class="pun">);</span><span class="pln">
      dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SET_PATIENT_LIST"</span><span class="pun">,</span><span class="pln"> payload</span><span class="pun">:</span><span class="pln"> patients </span><span class="pun">});</span><span class="pln">
    </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="pln">e</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  fetchPatientList</span><span class="pun">();</span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="pun">[</span><span class="pln">dispatch</span><span class="pun">]);</span></pre>

<p>
	<strong>تحذير</strong>! لن تُقيَّم البيانات عندما نمرر النوع كمعامل إلى المكتبة axios. وهو خطر تمامًا وخاصة إن كنت تستخدم واجهة برمجية خارجية. لتفادي ذلك يمكنك إنشاء دوال تقييم مخصصة تتحمل عبء التقييم وتعيد النوع الصحيح، أو يمكنك استخدام "حاميات النوع". ستجد أيضًا عدة مكتبات تزوّدك بأساليب لتقييم البيانات ضمن أنواع مختلفة من التخطيطات، مثل المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/gcanti/io-ts" rel="external nofollow">io-ts</a>. لكننا وتوخيًا للبساطة سنثق أننا سنحصل على البيانات بشكلها الصحيح من الواجهة الخلفية.
</p>

<p>
	وطالما أن تطبيقنا صغير، سنحدِّث الحالة باستدعاء دالة الإيفاد التي يؤمنها لنا الخطاف <code>useStateValue</code>. وسيساعدنا المصرّف بالتأكد من أننا أوفدنا الأفعال بما يوافق النوع Action الذي يضم قيمة محددة مسبقًا من النوع string وحمولة من البيانات payload.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_81" style="">
<span class="pln">dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SET_PATIENT_LIST"</span><span class="pun">,</span><span class="pln"> payload</span><span class="pun">:</span><span class="pln"> patients </span><span class="pun">});</span></pre>

<h2>
	التمارين 9.16 - 9.18
</h2>

<p>
	سنضيف قريبًا النوع Entry إلى التطبيق والذي يمثّل مُدخلًا على شكل ملخّص بسيط عن المريض. يتكون الملخص من نص وصفي، وتاريخ الإنشاء، ومعلومات تتعلق بالاختصاصي الذي أنشأ الملخص ورمز التشخيص المحتمل. ترتبط شيفرة التشخيص بالرموز ICD-10 التي تُعيدها وصلة التخديم api/diagnosis/. سيكون ما ننفذه بسيطًا، إذ يعطي لكل مريض مصفوفة من المُدخلات.
</p>

<p>
	سنُجري بعض التحضيرات، قبل الشروع في العمل.
</p>

<h3>
	9.16 تطبيق إدارة المرضى: الخطوة 1
</h3>

<p>
	أنشئ وصلة تخديم على العنوان api/patients/:id/ تعيد كل المعلومات عن مريض، بما فيها مصفوفة المُدخلات الخاصة به والتي ستبقى فارغة لجميع المرضى. وسّع حاليًا الأنواع في الواجهة الخلفية على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_83" style="">
<span class="com">// eslint-disable-next-line @typescript-eslint/no-empty-interface</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> interface </span><span class="typ">Entry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> interface </span><span class="typ">Patient</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  ssn</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  occupation</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  gender</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">;</span><span class="pln">
  dateOfBirth</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  entries</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Entry</span><span class="pun">[]}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> type </span><span class="typ">PublicPatient</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Omit</span><span class="pun">&lt;</span><span class="typ">Patient</span><span class="pun">,</span><span class="pln"> </span><span class="str">'ssn'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'entries'</span><span class="pln"> </span><span class="pun">&gt;</span></pre>

<p>
	ينبغي أن تبدو الاستجابة كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67124" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/backend_response_patients_05.png.bc2c9aa75e03d43096940f32205b4514.png" rel=""><img alt="backend_response_patients_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67124" data-unique="dgkgjmqla" src="https://academy.hsoub.com/uploads/monthly_2021_05/backend_response_patients_05.png.bc2c9aa75e03d43096940f32205b4514.png"></a>
</p>

<h3>
	9.17 تطبيق إدارة المرضى: الخطوة 2.
</h3>

<p>
	أنشئ صفحة لإظهار المعلومات الكاملة عن مريض ضمن الواجهة الأمامية.
</p>

<p>
	ينبغي أن يكون المستخدم قادرًا على الوصول إلى معلومات المريض بالنقر على اسم المريض مثلًا.
</p>

<p>
	أحضر البيانات من وصلة التخديم التي أنشأتها في التمرين السابق. أضف المعلومات التي ستحضرها عن المريض إلى حالة التطبيق. لا تحضر المعلومات إن كانت موجودة مسبقًا في حالة التطبيق، أي في الحالة التي يعرض فيها المستخدم معلومات مريض أكثر من مرة.
</p>

<p>
	طالما أننا سنستخدم حالة التطبيق ضمن سياق العمل، عليك أن تُعرّف فعلًا جديدًا لتحديث بيانات مريض محدد.
</p>

<p>
	يستخدم التطبيق المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/" rel="external nofollow">Semantic UI React</a> لإضافة التنسيقات إليه. وهي مكتبة مشابهة كثيرًا للمكتبتين <a data-ss1621337058="1" data-ss1621337687="1" href="https://react-bootstrap.github.io/" rel="external nofollow">React Bootstrap</a> و<a data-ss1621337058="1" data-ss1621337687="1" href="https://material-ui.com/" rel="external nofollow">MaterialUI</a> اللتان تعاملنا معهما في القسم 7. يمكنك استخدامهما لتنسيق المكوّن الجديد، وهذا أمر يعود إليك، فاهتمامنا ينصب الآن على TS.
</p>

<p>
	ويستخدم التطبيق أيضًا المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://reacttraining.com/react-router/web/guides/quick-start" rel="external nofollow">react router</a> للتحكم بإظهار واجهات العرض على الشاشة. عليك إلقاء نظرة على القسم 7 إن لم تكن متمكنًا من فهم آلية عمل الموجّهات routers.
</p>

<p>
	ستبدو النتيجة كالتالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67127" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step2_06.png.182587302bfa1c89bdf120e80910b707.png" rel=""><img alt="patientor_step2_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67127" data-unique="jbyak942r" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step2_06.png.182587302bfa1c89bdf120e80910b707.png"></a>
</p>

<p>
	يظهر جنس المريض باستخدام المكون <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/elements/icon/#gendersicons-can-represent-genders-or-types-of-sexuality" rel="external nofollow">Icon</a> من المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/" rel="external nofollow">Semantic UI React</a>.
</p>

<p>
	<strong>ملاحظة</strong>: لتصل إلى المُعرِّف بكتابة عنوان المورد، عليك إعطاء الخطاف <a data-ss1621337058="1" data-ss1621337687="1" href="https://reacttraining.com/react-router/web/api/Hooks/useparams" rel="external nofollow">useParams</a> معامل من نوع مناسب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_85" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> id </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useParams</span><span class="pun">&lt;{</span><span class="pln"> id</span><span class="pun">:</span><span class="pln"> string </span><span class="pun">}&gt;();</span></pre>

<h3>
	9.18 تطبيق إدارة المرضى: الخطوة 3.
</h3>

<p>
	سننشئ حاليًا كائنات أفعال <code>action</code> في أي مكان نوفد إليه هذه الأفعال. إذ يمتلك المكوّن <code>App</code> مثلًا دالة الإيفاد التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_87" style="">
<span class="pln">dispatch</span><span class="pun">({</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"SET_PATIENT_LIST"</span><span class="pun">,</span><span class="pln"> payload</span><span class="pun">:</span><span class="pln"> patientListFromApi
</span><span class="pun">});</span></pre>

<p>
	أعد كتابة الشيفرة مستخدمًا دوال <a data-ss1621337058="1" data-ss1621337687="1" href="https://fullstackopen.com/en/part6/flux_architecture_and_redux#action-creators" rel="external nofollow">توليد الأفعال</a> المُعرّفة ضمن الملف "reducer.tsx".
</p>

<p>
	سيتغير المكوِّن <code>App</code> مثلًا على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_89" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> useStateValue</span><span class="pun">,</span><span class="pln"> setPatientList </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"./state"</span><span class="pun">;</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

dispatch</span><span class="pun">(</span><span class="pln">setPatientList</span><span class="pun">(</span><span class="pln">patientListFromApi</span><span class="pun">));</span></pre>

<h2>
	مدخلات كاملة
</h2>

<p>
	أنجزنا في التمرين 9.12 وصلة تخديم لإحضار تشخيص مريض، لكننا لم نستخدمها بعد. من الجيد توسيع بياناتنا قليلُا بعد أن أصبح لدينا صفحة لعرض معلومات المرضى. لنضف إذًا حقلًا من النوع Entry إلى بيانات المريض، تتضمن مدخلاته الدوائية مع التشخيص المحتمل.
</p>

<p>
	لنفصل بنية بيانات المرضى السابقة عن الواجهة الخلفية ونستخدم <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/fullstack-hy2020/misc/blob/master/patients.ts" rel="external nofollow">الشكل الجديد الموسَّع.</a>
</p>

<p>
	<strong>ملاحظة</strong>: إن تنسيق البيانات هذه المرة بالصيغة "ts." وليس بالصيغة ".json". كما أن النوعين <code>Gender</code> و<code>Patient</code> جاهزين مسبقًا، لذلك كل ما عليك الآن هو تصحيح مسار إدراجهما إن اقتضت الحاجة.
</p>

<p>
	لننشئ النوع Entry بشكل ملائم بناء على البيانات المتوفرة.
</p>

<p>
	لو ألقينا الآن نظرة أقرب على البيانات المتوفرة، سنجد أن المُدخلات مختلفة عن بعضها قليلًا. لاحظ الاختلافات بين أول مدخلين على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_91" style="">
<span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'d811e46d-70b3-4d90-b090-4535c7cf8fb1'</span><span class="pun">,</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2015-01-02'</span><span class="pun">,</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Hospital'</span><span class="pun">,</span><span class="pln">
  specialist</span><span class="pun">:</span><span class="pln"> </span><span class="str">'MD House'</span><span class="pun">,</span><span class="pln">
  diagnosisCodes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'S62.5'</span><span class="pun">],</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln">
    </span><span class="str">"Healing time appr. 2 weeks. patient doesn't remember how he got the injury."</span><span class="pun">,</span><span class="pln">
  discharge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2015-01-16'</span><span class="pun">,</span><span class="pln">
    criteria</span><span class="pun">:</span><span class="pln"> </span><span class="str">'Thumb has healed.'</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> </span><span class="str">'fcd59fa6-c4b4-4fec-ac4d-df4fe1f85f62'</span><span class="pun">,</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-08-05'</span><span class="pun">,</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">'OccupationalHealthcare'</span><span class="pun">,</span><span class="pln">
  specialist</span><span class="pun">:</span><span class="pln"> </span><span class="str">'MD House'</span><span class="pun">,</span><span class="pln">
  employerName</span><span class="pun">:</span><span class="pln"> </span><span class="str">'HyPD'</span><span class="pun">,</span><span class="pln">
  diagnosisCodes</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">'Z57.1'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Z74.3'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'M51.2'</span><span class="pun">],</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln">
    </span><span class="str">'Patient mistakenly found himself in a nuclear plant waste site without protection gear. Very minor radiation poisoning. '</span><span class="pun">,</span><span class="pln">
  sickLeave</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    startDate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-08-05'</span><span class="pun">,</span><span class="pln">
    endDate</span><span class="pun">:</span><span class="pln"> </span><span class="str">'2019-08-28'</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنرى أن بعض الحقول متطابقة لكن المُدخل الأول يمتلك الحقل <code>discharge</code> والثاني يمتلك الحقلين <code>employerName</code> و<code>sickLeave</code>. وبشكل عام تحتوي جميع المدخلات حقول مشتركة وحقول خاصة.
</p>

<p>
	وبالنظر إلى الحقل <code>type</code>، سنجد ثلاثة أشكال للمدخلات تشير إلى حاجتنا إلى ثلاثة أنواع منفصلة:
</p>

<ul>
<li>
		<code>OccupationalHealthcare</code>
	</li>
	<li>
		<code>Hospital</code>
	</li>
	<li>
		<code>HealthCheck</code>.
	</li>
</ul>
<p>
	تشترك المدخلات بعدة حقول، وبالتالي من المناسب إنشاء واجهة نوع أساسي تدعى "Entry" قابلة للتوسّع بإضافة حقول خاصة لكل نوع.
</p>

<p>
	تُعَدّ الحقول الآتية مشتركةً بين كل المدخلات:
</p>

<ul>
<li>
		 <code>id</code>
	</li>
	<li>
		<code>description</code>
	</li>
	<li>
		<code>date</code>
	</li>
	<li>
		<code>specialist</code>
	</li>
</ul>
<p>
	ويبدو أن الحقل <code>diagnosesCodes</code> موجود فقط في المدخلات من النوعين <code>OccupationalHealthcare</code> و<code>Hospital</code>. وطالما أنه لا يستخدم دائمًا حتى في هذين النوعين، فسنفترض أنه حقل اختياري. ويمكن إضافته إلى النوع <code>HealthCheck</code> أيضًا، إذ ليس من الضرورة استخدامه في أي من المدخلات الثلاث.
</p>

<p>
	ستبدو واجهة النوع الأساسي كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_93" style="">
<span class="pln">interface </span><span class="typ">BaseEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  specialist</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  diagnosisCodes</span><span class="pun">?:</span><span class="pln"> string</span><span class="pun">[];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لو أردنا تهيئة الواجهة بشكل أفضل، ولعلمنا أن النوع Diagnoses قد عُرِّف مسبقًا في الواجهة الخلفية، من الممكن إذًا الإشارة مباشرة إلى حقل الشيفرة للنوع Diagnoses في حال تغيّر نوعه لسبب ما. سننفذ ذلك على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_95" style="">
<span class="pln">interface </span><span class="typ">BaseEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  description</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  specialist</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  diagnosisCodes</span><span class="pun">?:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">Diagnosis</span><span class="pun">[</span><span class="str">'code'</span><span class="pun">]&gt;;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وتذكّر أن <code>&lt;Array&lt;Type</code> هي صيغة بديلة للتعليمة <code>[]Type</code>. ومن الأفضل والأوضح في حالات كهذه أن نستخدم المصفوفة، لأن استخدام الخيار الآخر سيدفعنا إلى تعريف النوع بالعبارة DiagnosisCode والتي تبدو غريبة بعض الشيء.
</p>

<p>
	يمكننا الآن وبعد تعريف النوع الأساسي Entry، أن ننشئ الأنواع Entry الموسّعة التي سنستخدمها فعليًا. وسنبدأ بإنشاء النوع HealthCheckEntry.
</p>

<p>
	تحتوي المدخلات من النوع HealthCheck على الحقل <code>HealthCheckRating</code> الذي يأخذ قيمًا صحيحة بين 0 و 3. تعني القيمة 0 أن المريض بصحة جيدة، أما القيمة 3 فتعني أن المريض بحالة حرجة. وهذا ما يجعل استخدام التعداد مثاليًا. وبناء على المعطيات السابقة يمكن تعريف النوع HealthCheckEntry على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_97" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">HealthCheckRating</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="str">"Healthy"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"LowRisk"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"HighRisk"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"CriticalRisk"</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

interface </span><span class="typ">HealthCheckEntry</span><span class="pln"> extends </span><span class="typ">BaseEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"HealthCheck"</span><span class="pun">;</span><span class="pln">
  healthCheckRating</span><span class="pun">:</span><span class="pln"> </span><span class="typ">HealthCheckRating</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يبقى علينا الآن إنشاء النوعين OccupationalHealthcareEntry وHospitalEntry ومن ثم نضم الأنواع الثلاثة ونصدّرها كنوع موحّد Entry كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_99" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">Entry</span><span class="pln"> </span><span class="pun">=</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">HospitalEntry</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">OccupationalHealthcareEntry</span><span class="pln">
  </span><span class="pun">|</span><span class="pln"> </span><span class="typ">HealthCheckEntry</span><span class="pun">;</span></pre>

<h2>
	التمارين 9.19 - 9.22
</h2>

<h3>
	9.19 تطبيق إدارة المرضى: الخطوة 4
</h3>

<p>
	عّرف النوعين بما يتلائم مع البيانات الموجودة. تأكد أن الواجهة الخلفية ستعيد المُدخل المناسب عندما تتوجه لإحضار معلومات مريض محدد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67128" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step4_07.png.f130ea4ad159c0470a4a28e52015b826.png" rel=""><img alt="patientor_step4_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67128" data-unique="da1j5qees" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step4_07.png.f130ea4ad159c0470a4a28e52015b826.png"></a>
</p>

<p>
	استخدم الأنواع بشكل صحيح في الواجهة الخلفية. لا حاجة الآن لتقييم بيانات كل الحقول في الواجهة الخلفية، ويكفي التحقق أن الحقل <code>type</code> سيحتوي قيمة من النوع الصحيح.
</p>

<h3>
	9.20 تطبيق إدارة المرضى: الخطوة 5
</h3>

<p>
	وسّع صفحة المريض في الواجهة الأمامية لإظهار قائمة تضم تاريخ ووصف ورمز التشخيص لكل مدخلات المريض.
</p>

<p>
	يمكنك استخدام نفس النوع Entry الذي عرّفناه الآن ضمن الواجهة الأمامية. ويكفي في هذه التمارين أن ننقل تعريف الأنواع كما هو من الواجهة الخلفية إلى الأمامية (نسخ/لصق).
</p>

<p>
	قد يبدو حلك قريبًا من التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67126" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/pateintor_step5_08.png.3aebdb7ab634313e0258cf5e28f42327.png" rel=""><img alt="pateintor_step5_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67126" data-unique="4yjkozmms" src="https://academy.hsoub.com/uploads/monthly_2021_05/pateintor_step5_08.png.3aebdb7ab634313e0258cf5e28f42327.png"></a>
</p>

<h3>
	9.21 تطبيق إدارة المرضى: الخطوة 6
</h3>

<p>
	أحضر التشخيص ثم أضفه إلى حالة التطبيق من وصلة التخديم api/diagnosis/. استخدم بيانات التشخيص الجديدة لإظهار توصيف رموز التشخيصات للمريض.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67129" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step6_09.png.0cc225b5fd8f20ebf4cdf9668920f632.png" rel=""><img alt="patientor_step6_09.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67129" data-unique="s6b5vbx98" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step6_09.png.0cc225b5fd8f20ebf4cdf9668920f632.png"></a>
</p>

<h3>
	9.22 تطبيق إدارة المرضى: الخطوة 7
</h3>

<p>
	وسّع قائمة المدخلات في صفحة المريض لتتضمن تفاصيل أكثر باستخدام مكوّن جديد يُظهِر بقية المعلومات الموجودة ضمن مدخلات المريض ومميزًا الأنواع عن بعضها.
</p>

<p>
	يمكنك أن تستخدمعلى سبيل المثال المكوّن <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/elements/icon/" rel="external nofollow">Icon</a> أو أي مكوًن آخر من مكوّنات المكتبة <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/" rel="external nofollow">SemanticUI</a> للحصول على مظهر مناسب لقائمتك.
</p>

<p>
	ينبغي تنفيذ عملية تصيير شرطية باستخدام البنية switch case وآلية التحقق الشاملة من الأنواع لكي لا تنس أية حالة.
</p>

<p>
	تأمل الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67130" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step7_10.png.05cebf2b472bf035a506e0bce2fffc64.png" rel=""><img alt="patientor_step7_10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67130" data-unique="ao3h7ux1l" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step7_10.png.05cebf2b472bf035a506e0bce2fffc64.png"></a>
</p>

<p>
	ستبدو قائمة المدخلات قريبة من الشكل التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67131" data-ss1621337058="1" data-ss1621337687="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step7_entries_list_11.png.c58d7c165d38707563dea2b914f90621.png" rel=""><img alt="patientor_step7_entries_list_11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67131" data-unique="jdygtyn7k" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step7_entries_list_11.png.c58d7c165d38707563dea2b914f90621.png"></a>
</p>

<h2>
	نموذج لإضافة مريض
</h2>

<p>
	قد يكون التعامل مع النماذج مزعجًا أحيانًا في ، لذلك قررنا استخدام الحزمة <a data-ss1621337058="1" data-ss1621337687="1" href="https://jaredpalmer.com/formik/docs/overview" rel="external nofollow">Formik</a> لإنشاء نموذج لإضافة مريض في تطبيقنا. فيما سيأتي تقديم بسيط اجتزأناه من توثيق :
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		Formik هي مكتبة صغيرة تساعدك في تطوير الأقسام الثلاث الأكثر إزعاجًا
	</p>

	<blockquote class="ipsQuote" data-ipsquote="">
		<div class="ipsQuote_citation">
			اقتباس
		</div>

		<ul>
<li>
				إحضار المعلومات من وإلى حالة التطبيق
			</li>
			<li>
				التقييم وإظهار رسائل الخطأ
			</li>
			<li>
				التعامل مع عمليات إرسال معلومات النموذج
			</li>
		</ul>
</blockquote>

	<p>
		ستنظم Formik الأشياء بتجميع العمليات السابقة في مكان واحد، وستغدو الاختبارات و إعادة كتابة الشيفرة وتقييم النماذج أمرًا يسيرًا.
	</p>
</blockquote>

<p>
	يمكنك إيجاد شيفرة النموذج في الملف src/AddPatientModal/AddPatientForm.tsx ،كما يمكنك إيجاد الدوال المساعدة لهذا النموذج في الملف src/AddPatientModal/FormField.tsx.
</p>

<p>
	لو نظرت إلى الملف AddPatientForm.tsx لوجدت أننا أنشأنا نوعًا لقيم النموذج يدعى PatientFormValues. يمثل هذا النوع نسخة معدلة عن النوع Patient بعد حذف الخاصيتين <code>id</code> و <code>entries</code>. فلا نريد أن يرسل المستخدم المعلومات الموجودة ضمن هاتين الخاصيتين عند إنشاء مريض جديد. فالمعرِّف <code>id</code> ستنشئه الواجهة الخلفية والمدخلات <code>entries</code> لا يمكن إضافتها إلا لمريض موجود مسبقًا.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_101" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">PatientFormValues</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Omit</span><span class="pun">&lt;</span><span class="typ">Patient</span><span class="pun">,</span><span class="pln"> </span><span class="str">"id"</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">"entries"</span><span class="pun">&gt;;</span></pre>

<p>
	سنصرّح تاليًا عن خصائص المكوّن الخاص بالنموذج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_103" style="">
<span class="pln">interface </span><span class="typ">Props</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  onSubmit</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">values</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PatientFormValues</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">void</span><span class="pun">;</span><span class="pln">
  onCancel</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">void</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتطلب المكوّن وجود خاصيتين: <code>onSubmit</code> و<code>onCancel</code>. وكلاهما دالة استدعاء لا تعيد قيمًا. ينبغي أن تتلقى الدالة كائنًا من النمط "PatientFormValues" كمعامل لكي تتمكن من معالجة قيم النموذج.
</p>

<p>
	بالنظر إلى مكوّن الدالة <code>AddPatientForm</code>، ستجد أننا ربطنا به خصائصه، ومن ثم فككنا <code>onSubmit</code> و<code>onCancel</code> من هذه الخصائص.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_105" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">AddPatientForm</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">Props</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onSubmit</span><span class="pun">,</span><span class="pln"> onCancel </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	قبل أن نكمل، لنلق نظرة على الدوال المساعدة في نموذجنا والموجودة في الملف <code>FormField.tsx</code>. لو تحققت من الأشياء التي يصدرها الملف، ستجد النوع GenderOption ومكوني الدوال <code>SelectField</code> و<code>TextField</code>.
</p>

<p>
	لنلق نظرة على مكوِّن الدالة <code>SelectField</code> والأنواع المتعلقة به. أنشأنا أولًا نوعًا معممًا لكل كائن خيارات يتضمن قيمة وتسمية. هذه هي أنواع كائنات الخيارات التي سنسمح بها في نموذجنا ضمن حقل الخيارات. وطالما أن الخيار الوحيد الذي سنسمح به هو جنس المريض سنجعل القيمة <code>value</code> من النوع Gender.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_107" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">GenderOption</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">;</span><span class="pln">
  label</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	أعطينا المتغير <code>genderOptions</code> في الملف AddPatientForm.tsx النوع GenderOption وصرحنا أنه مصفوفة تحتوي على كائنات من النوع GenderOption.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_109" style="">
<span class="kwd">const</span><span class="pln"> genderOptions</span><span class="pun">:</span><span class="pln"> </span><span class="typ">GenderOption</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">.</span><span class="typ">Male</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Male"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">.</span><span class="typ">Female</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Female"</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln"> value</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">.</span><span class="typ">Other</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Other"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="pun">];</span></pre>

<p>
	لاحظ إيضًا النوع SelectFieldProps. إذ يقوم بتعريف نوع لخصائص مكوِّن الدالة <code>SelectField</code>. سترى أن الخيارات عبارة عن مصفوفة من النوع GenderOption.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_111" style="">
<span class="pln">type </span><span class="typ">SelectFieldProps</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  label</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  options</span><span class="pun">:</span><span class="pln"> </span><span class="typ">GenderOption</span><span class="pun">[];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	إن عمل مكوِّن الدالة SelectField واضح تمامًا. فهو يصيّر التسمية ويختار عنصرًا، ومن ثم يعطي كل الخيارات المتاحة لهذا العنصر ( قيم هذه الخيارات وتسمياتها).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_113" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">SelectField</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">SelectFieldProps</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln">
  name</span><span class="pun">,</span><span class="pln">
  label</span><span class="pun">,</span><span class="pln">
  options
</span><span class="pun">}:</span><span class="pln"> </span><span class="typ">SelectFieldProps</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Field</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln"> as</span><span class="pun">=</span><span class="str">"select"</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> className</span><span class="pun">=</span><span class="str">"ui dropdown"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">options</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">option </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="pln">option key</span><span class="pun">={</span><span class="pln">option</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln"> value</span><span class="pun">={</span><span class="pln">option</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}&gt;</span><span class="pln">
          </span><span class="pun">{</span><span class="pln">option</span><span class="pun">.</span><span class="pln">label </span><span class="pun">||</span><span class="pln"> option</span><span class="pun">.</span><span class="pln">value</span><span class="pun">}</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="pln">option</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">))}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Field</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Field</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	لننتقل الآن إلى مكوِّن الدالة TextField. يُصيِّر هذا المكوّن الكائن <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/collections/form/" rel="external nofollow">Form.Field</a> من المكتبة SemanticUI إلى تسمية ومكوّن <a data-ss1621337058="1" data-ss1621337687="1" href="https://jaredpalmer.com/formik/docs/api/field" rel="external nofollow">Field</a> من المكتبة Formik. يتلقى هذا المكوًن القيمة <code>name</code> والقيمة <code>placeholder</code> كخصائص.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_115" style="">
<span class="pln">interface </span><span class="typ">TextProps</span><span class="pln"> extends </span><span class="typ">FieldProps</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  label</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  placeholder</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">TextProps</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> field</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">,</span><span class="pln"> placeholder </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Field</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">label</span><span class="pun">&gt;{</span><span class="pln">label</span><span class="pun">}&lt;/</span><span class="pln">label</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln"> placeholder</span><span class="pun">={</span><span class="pln">placeholder</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{...</span><span class="pln">field</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div style</span><span class="pun">={{</span><span class="pln"> color</span><span class="pun">:</span><span class="str">'red'</span><span class="pln"> </span><span class="pun">}}&gt;</span><span class="pln">
      </span><span class="pun">&lt;</span><span class="typ">ErrorMessage</span><span class="pln"> name</span><span class="pun">={</span><span class="pln">field</span><span class="pun">.</span><span class="pln">name</span><span class="pun">}</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">.</span><span class="typ">Field</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">);</span></pre>

<p>
	لاحظ أننا استخدمنا المكوّن <a data-ss1621337058="1" data-ss1621337687="1" href="https://jaredpalmer.com/formik/docs/api/errormessage" rel="external nofollow">ErrorMessage</a> من المكتبة Formik لتصيير رسالة خطأ تتعلق بالقيمة المدخلة إن اقتضى الأمر. ينفذ المكوّن كل ما يلزم خلف الستار، فلا حاجة لكتابة شيفرة خاصة لذلك.
</p>

<p>
	من الممكن أيضًا الاحتفاظ برسالة الخطأ ضمن المكوّن باستخدام الخاصيّة <code>form</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_117" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">TextField</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">TextProps</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> field</span><span class="pun">,</span><span class="pln"> label</span><span class="pun">,</span><span class="pln"> placeholder</span><span class="pun">,</span><span class="pln"> form </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">form</span><span class="pun">.</span><span class="pln">errors</span><span class="pun">);</span><span class="pln"> 
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنعود الآن إلى مكوّن النموذج الفعلي AddPatientForm.tsx. سيصيّر مكون الدالة <code>AddPatientForm</code> <a data-ss1621337058="1" data-ss1621337687="1" href="https://jaredpalmer.com/formik/docs/api/formik" rel="external nofollow">مكوّن Formik</a>. سيغلّف هذا المكون بقية المكوّنات ويتطلب خاصيتين <code>initialValues</code> و<code>onSubmit</code>. شيفرة دالة الخصائص واضحة تمامًا. سيتعقب مكوِّن Formik حالة النموذج وسيظهر هذه الحالة بالإضافة إلى عدة توابع قابلة لإعادة الاستخدام ومعالجات الأحداث ضمن النموذج عن طريق الخصائص.
</p>

<p>
	نستخدم أيضًا الخاصية الاختيارية <code>valiate</code> التي تقبل دالة تقييم وتعيد كائنًا يتضمن الأخطاء المحتملة. نتحقق في نموذجنا أن الحقول النصية ليست فارغة، لكن بالإمكان أن نضيف بعض المعايير الأخرى للتقييم كالتأكد من صحة رقم الضمان الاجتماعي على سبيل المثال. يمكن لرسائل الخطأ التي تحددها دالة التقييم أن تُعرض ضمن مكوّن <code>ErrorMessage</code> الخاص بكل حقل.
</p>

<p>
	لنلق نظرة أولًا على المكوّن بشكله الكامل. ثم سنناقش بعدها أقسامه المختلفة بشيء من التفصيل.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_119" style="">
<span class="pln">interface </span><span class="typ">Props</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  onSubmit</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">values</span><span class="pun">:</span><span class="pln"> </span><span class="typ">PatientFormValues</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">void</span><span class="pun">;</span><span class="pln">
  onCancel</span><span class="pun">:</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">void</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="typ">AddPatientForm</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">Props</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onSubmit</span><span class="pun">,</span><span class="pln"> onCancel </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Formik</span><span class="pln">
      initialValues</span><span class="pun">={{</span><span class="pln">
        name</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        ssn</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        dateOfBirth</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        occupation</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
        gender</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Gender</span><span class="pun">.</span><span class="typ">Other</span><span class="pln">
      </span><span class="pun">}}</span><span class="pln">
      onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}</span><span class="pln">
      validate</span><span class="pun">={</span><span class="pln">values </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> requiredError </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Field is required"</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">const</span><span class="pln"> errors</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">[</span><span class="pln">field</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">]:</span><span class="pln"> string </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{};</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">values</span><span class="pun">.</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          errors</span><span class="pun">.</span><span class="pln">name </span><span class="pun">=</span><span class="pln"> requiredError</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">values</span><span class="pun">.</span><span class="pln">ssn</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          errors</span><span class="pun">.</span><span class="pln">ssn </span><span class="pun">=</span><span class="pln"> requiredError</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">values</span><span class="pun">.</span><span class="pln">dateOfBirth</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          errors</span><span class="pun">.</span><span class="pln">dateOfBirth </span><span class="pun">=</span><span class="pln"> requiredError</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">values</span><span class="pun">.</span><span class="pln">occupation</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          errors</span><span class="pun">.</span><span class="pln">occupation </span><span class="pun">=</span><span class="pln"> requiredError</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> errors</span><span class="pun">;</span><span class="pln">
      </span><span class="pun">}}</span><span class="pln">
    </span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">{({</span><span class="pln"> isValid</span><span class="pun">,</span><span class="pln"> dirty </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
          </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pln"> className</span><span class="pun">=</span><span class="str">"form ui"</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln">
              label</span><span class="pun">=</span><span class="str">"Name"</span><span class="pln">
              placeholder</span><span class="pun">=</span><span class="str">"Name"</span><span class="pln">
              name</span><span class="pun">=</span><span class="str">"name"</span><span class="pln">
              component</span><span class="pun">={</span><span class="typ">TextField</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln">
              label</span><span class="pun">=</span><span class="str">"Social Security Number"</span><span class="pln">
              placeholder</span><span class="pun">=</span><span class="str">"SSN"</span><span class="pln">
              name</span><span class="pun">=</span><span class="str">"ssn"</span><span class="pln">
              component</span><span class="pun">={</span><span class="typ">TextField</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln">
              label</span><span class="pun">=</span><span class="str">"Date Of Birth"</span><span class="pln">
              placeholder</span><span class="pun">=</span><span class="str">"YYYY-MM-DD"</span><span class="pln">
              name</span><span class="pun">=</span><span class="str">"dateOfBirth"</span><span class="pln">
              component</span><span class="pun">={</span><span class="typ">TextField</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Field</span><span class="pln">
              label</span><span class="pun">=</span><span class="str">"Occupation"</span><span class="pln">
              placeholder</span><span class="pun">=</span><span class="str">"Occupation"</span><span class="pln">
              name</span><span class="pun">=</span><span class="str">"occupation"</span><span class="pln">
              component</span><span class="pun">={</span><span class="typ">TextField</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">SelectField</span><span class="pln">
              label</span><span class="pun">=</span><span class="str">"Gender"</span><span class="pln">
              name</span><span class="pun">=</span><span class="str">"gender"</span><span class="pln">
              options</span><span class="pun">={</span><span class="pln">genderOptions</span><span class="pun">}</span><span class="pln">
            </span><span class="pun">/&gt;</span><span class="pln">
            </span><span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pln"> floated</span><span class="pun">=</span><span class="str">"left"</span><span class="pln"> width</span><span class="pun">={</span><span class="lit">5</span><span class="pun">}&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">onCancel</span><span class="pun">}</span><span class="pln"> color</span><span class="pun">=</span><span class="str">"red"</span><span class="pun">&gt;</span><span class="pln">
                  </span><span class="typ">Cancel</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pln"> floated</span><span class="pun">=</span><span class="str">"right"</span><span class="pln"> width</span><span class="pun">={</span><span class="lit">5</span><span class="pun">}&gt;</span><span class="pln">
                </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln">
                  type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln">
                  floated</span><span class="pun">=</span><span class="str">"right"</span><span class="pln">
                  color</span><span class="pun">=</span><span class="str">"green"</span><span class="pln">
                  disabled</span><span class="pun">={!</span><span class="pln">dirty </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isValid</span><span class="pun">}</span><span class="pln">
                </span><span class="pun">&gt;</span><span class="pln">
                  </span><span class="typ">Add</span><span class="pln">
                </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
              </span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">&gt;</span><span class="pln">
            </span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">&gt;</span><span class="pln">
        </span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Formik</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="typ">AddPatientForm</span><span class="pun">;</span></pre>

<p>
	يمتلك مكوّن التغليف دالة تعيد محتويات النموذج كمكوِّن ابن child component. ونستخدم العنصر <a data-ss1621337058="1" data-ss1621337687="1" href="https://jaredpalmer.com/formik/docs/api/form" rel="external nofollow">Form</a> من المكتبة Formik لتصيير العناصر الفعلية للنموذج. سنضع داخل هذا العنصر مكونات الدوال <code>TextField</code> و<code>SelectField</code> التي أنشأناها في الملف FormField.tsx.
</p>

<p>
	سننشئ في النهاية زرين: الأول لإلغاء إرسال معلومات النموذج، وآخر لإرسالها. يستدعي الزر الأول الدالة <code>onCancel</code> مباشرة، ويحرّض الزر الثاني الحدث onSubmitt للمكتبة Formik الذي يستدعي بدوره الدالة <code>onSubmitt</code> من خصائص المكوّن. سيُفعَّل زر الإرسال إن كان النموذج صالحًا (يعيد القيمة valid) و مستعملًا (يعيد القيمة dirty). أي عندما يضيف المستخدم معلومات ضمن بعض الحقول.
</p>

<p>
	نعالج عملية إرسال بيانات النموذج باستخدام المكتبة لأنها تسمح لنا باستدعاء دالة التقييم قبل الشروع فعليًا بإرسال البيانات. فإن أعادة دالة التقييم أية أخطاء، سيلغى الإرسال.
</p>

<p>
	وُضع الزرين داخل العنصر <a data-ss1621337058="1" data-ss1621337687="1" href="https://react.semantic-ui.com/collections/grid/" rel="external nofollow">Grid</a> من المكتبة Formik لضبطهما متجاورين بطريقة سهلة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_121" style="">
<span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pln"> floated</span><span class="pun">=</span><span class="str">"left"</span><span class="pln"> width</span><span class="pun">={</span><span class="lit">5</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"button"</span><span class="pln"> onClick</span><span class="pun">={</span><span class="pln">onCancel</span><span class="pun">}</span><span class="pln"> color</span><span class="pun">=</span><span class="str">"red"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="typ">Cancel</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pln"> floated</span><span class="pun">=</span><span class="str">"right"</span><span class="pln"> width</span><span class="pun">={</span><span class="lit">5</span><span class="pun">}&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Button</span><span class="pln"> type</span><span class="pun">=</span><span class="str">"submit"</span><span class="pln"> floated</span><span class="pun">=</span><span class="str">"right"</span><span class="pln"> color</span><span class="pun">=</span><span class="str">"green"</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="typ">Add</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="typ">Button</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">.</span><span class="typ">Column</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="typ">Grid</span><span class="pun">&gt;</span></pre>

<p>
	يُمرر الاستدعاء <code>onSubmit</code> من صفحة قائمة المرضى نزولًا إلى نموذج إضافة مريض، ليرسل طلب HTTP-POST إلى الواجهة الخلفية، ويضيف المريض الذي تعيده الواجهة الخلفية إلى حالة التطبيق ويغلق النموذج. إن أعادت الواجهة الخلفية خطأً، سيُعرض الخطأ على النموذج.
</p>

<p>
	تمثل الشيفرة التالية دالة الاستدعاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_123" style="">
<span class="kwd">const</span><span class="pln"> submitNewPatient </span><span class="pun">=</span><span class="pln"> async </span><span class="pun">(</span><span class="pln">values</span><span class="pun">:</span><span class="pln"> </span><span class="typ">FormValues</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> data</span><span class="pun">:</span><span class="pln"> newPatient </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> await axios</span><span class="pun">.</span><span class="pln">post</span><span class="pun">&lt;</span><span class="typ">Patient</span><span class="pun">&gt;(</span><span class="pln">
      </span><span class="pun">`</span><span class="pln">$</span><span class="pun">{</span><span class="pln">apiBaseUrl</span><span class="pun">}/</span><span class="pln">patients</span><span class="pun">`,</span><span class="pln">
      values
    </span><span class="pun">);</span><span class="pln">
    dispatch</span><span class="pun">({</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ADD_PATIENT"</span><span class="pun">,</span><span class="pln"> payload</span><span class="pun">:</span><span class="pln"> newPatient </span><span class="pun">});</span><span class="pln">
    closeModal</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">);</span><span class="pln">
    setError</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">response</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	ينبغي أن تكون قادرًا على إكمال بقية التمارين في هذا القسم بناء على المعلومات التي قدمناها. وإن راودتك أية شكوك، أعد قراءة الشيفرة الموجودة، فقد تعطيك تلميحًا لكيفية المتابعة.
</p>

<h2>
	التمارين 9.23 - 9.27
</h2>

<h3>
	9.23 تطبيق إدارة المرضى: الخطوة 8
</h3>

<p>
	صممنا التطبيق بحيث يمكن أن تجد عدة مدخلات لنفس المريض. لا توجد حتى الآن آلية في تطبيقنا لإضافة مُدخلات. عليك الآن أن تضيف وصلة تخديم على العنوان api/patients/:id/entries/ في الواجهة الخلفية، لتتمكن من إضافة مُدخل لمريض.
</p>

<p>
	تذكر أن هناك أنواع مختلفة من المدخلات في تطبيقنا، ويجب أن تدعم الواجهة الخلفية كل هذه الأنواع، وتحقق من وجود كل الحقول المطلوبة لكل نوع.
</p>

<h3>
	9.24 تطبيق إدارة المرضى: الخطوة 9
</h3>

<p>
	ستدعم الواجهة الخلفية الآن إضافة المُدخلات، ونريد أن ننفذ الوظيفة نفسها في الواجهة الأمامية. عليك إذًا إنشاء نموذج لإضافة مُدخل إلى سجل مريض. وتعتبر صفحة المريض مكانًا مناسبًا للوصول إلى هذا النموذج.
</p>

<p>
	يكفي في هذا التمرين أن تدعم نوعًا واحدًا من المدخلات، وليس مطلوبًا معالجة كافة الأخطاء الآن. إذ يكفي أن تنشئ بنجاح مدخلًا جديدًا عندما تُملأ حقول النموذج ببيانات صحيحة.
</p>

<p>
	ينبغي أن يُضاف مُدخل جديد إلى سجل المريض المحدد بعد نجاح عملية إرسال بيانات النموذج. كما ينبغي تحديث صفحة المريض ليظهر المُدخل الجديد.
</p>

<p>
	يمكنك إن أردت استخدام جزء من شيفرة نموذج إضافة مريض، لكن ذلك غير ضروري.
</p>

<p>
	انتبه إلى وجود المكوّن الجاهز <code>GiagnosesSelection</code> في الملف <a data-ss1621337058="1" data-ss1621337687="1" href="https://github.com/fullstack-hy2020/patientor/blob/master/src/AddPatientModal/FormField.tsx#L58" rel="external nofollow">FormField.tsx</a> حيث يمكنك استخدامه لضبط الحقل <code>diagnoses</code> بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_125" style="">
<span class="kwd">const</span><span class="pln"> </span><span class="typ">AddEntryForm</span><span class="pun">:</span><span class="pln"> </span><span class="typ">React</span><span class="pun">.</span><span class="pln">FC</span><span class="pun">&lt;</span><span class="typ">Props</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">({</span><span class="pln"> onSubmit</span><span class="pun">,</span><span class="pln"> onCancel </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">[{</span><span class="pln"> diagnoses </span><span class="pun">}]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> useStateValue</span><span class="pun">()</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="typ">Formik</span><span class="pln">
    initialValues</span><span class="pun">={{</span><span class="pln">
      </span><span class="com">/// ...</span><span class="pln">
    </span><span class="pun">}}</span><span class="pln">
    onSubmit</span><span class="pun">={</span><span class="pln">onSubmit</span><span class="pun">}</span><span class="pln">
    validate</span><span class="pun">={</span><span class="pln">values </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">/// ...</span><span class="pln">
    </span><span class="pun">}}</span><span class="pln">
  </span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">{({</span><span class="pln"> isValid</span><span class="pun">,</span><span class="pln"> dirty</span><span class="pun">,</span><span class="pln"> setFieldValue</span><span class="pun">,</span><span class="pln"> setFieldTouched </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
        </span><span class="pun">&lt;</span><span class="typ">Form</span><span class="pln"> className</span><span class="pun">=</span><span class="str">"form ui"</span><span class="pun">&gt;</span><span class="pln">
          </span><span class="com">// ...</span><span class="pln">

          </span><span class="pun">&lt;</span><span class="typ">DiagnosisSelection</span><span class="pln">
          setFieldValue</span><span class="pun">={</span><span class="pln">setFieldValue</span><span class="pun">}</span><span class="pln">
          setFieldTouched</span><span class="pun">={</span><span class="pln">setFieldTouched</span><span class="pun">}</span><span class="pln">
          diagnoses</span><span class="pun">={</span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="pln">diagnoses</span><span class="pun">)}</span><span class="pln">          </span><span class="pun">/&gt;</span><span class="pln">    
          </span><span class="com">// ...</span><span class="pln">
        </span><span class="pun">&lt;/</span><span class="typ">Form</span><span class="pun">&gt;</span><span class="pln">
      </span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}}</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="typ">Formik</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	كما يوجد أيضًا مكوّن جاهز يدعى <code>NumberField</code> للقيم العددية ضمن مجال محدد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3933_127" style="">
<span class="pun">&lt;</span><span class="typ">Field</span><span class="pln">
  label</span><span class="pun">=</span><span class="str">"healthCheckRating"</span><span class="pln">
  name</span><span class="pun">=</span><span class="str">"healthCheckRating"</span><span class="pln">
  component</span><span class="pun">={</span><span class="typ">NumberField</span><span class="pun">}</span><span class="pln">
  min</span><span class="pun">={</span><span class="lit">0</span><span class="pun">}</span><span class="pln">
  max</span><span class="pun">={</span><span class="lit">3</span><span class="pun">}</span><span class="pln">
</span><span class="pun">/&gt;</span></pre>

<h3>
	9.25 تطبيق إدارة المرضى: الخطوة 10
</h3>

<p>
	وسّع التطبيق ليُظهر رسالة خطأ إن كانت إحدى القيم المطلوبة مفقودة أو بتنسيق غير صحيح.
</p>

<h3>
	9.26 تطبيق إدارة المرضى: الخطوة 11
</h3>

<p>
	وسّع تطبيقك ليدعم نوعين من المُدخلات، ويُظهر رسالة خطأ إن كانت إحدى القيم المطلوبة مفقودة أو بتنسيق غير صحيح. لا تهتم بالأخطاء المحتملة التي قد تحملها استجابة الخادم.
</p>

<p>
	تقتضي الطريقة الأسهل -وبالطبع ليست الأكثر أناقة- لتنفيذ التمرين أن تنشئ نموذجًا منفصلًا لكل مدخل، فقد تواجهك بعض الصعوبات في التعامل مع الأنواع إن استخدمت نمودجًا واحدًا.
</p>

<h3>
	9.27 تطبيق إدارة المرضى: الخطوة 12
</h3>

<p>
	وسّع التطبيق ليدعم كل أنواع المُدخلات، ويُظهر رسالة خطأ إن كانت إحدى القيم المطلوبة مفقودة أو بتنسيق غير صحيح. لا تهتم بالأخطاء المحتملة التي قد تحملها استجابة الخادم.
</p>

<p>
	وهكذا نكون قد وصلنا إلى التمرين الأخير في هذا الفصل وحان الوقت لتسليم الحلول إلى GitHub، والإشارة إلى التمارين التي أنجزتها في <a data-ss1621337058="1" data-ss1621337687="1" href="https://studies.cs.helsinki.fi/stats/courses/fullstackopen" rel="external nofollow">منظومة تسليم التمارين</a>.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1621337058="1" data-ss1621337687="1" href="https://fullstackopen.com/en/part9/react_with_types" rel="external nofollow">React with Types</a> من سلسلة <a data-ss1621337058="1" data-ss1621337687="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1218</guid><pubDate>Mon, 24 May 2021 11:09:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x62A;&#x64A; &#x62A;&#x648;&#x641;&#x631;&#x647;&#x627; TypeScript &#x641;&#x64A; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; express</title><link>https://academy.hsoub.com/programming/javascript/typescript/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AA%D9%8A-%D8%AA%D9%88%D9%81%D8%B1%D9%87%D8%A7-typescript-%D9%81%D9%8A-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-express-r1216/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/6083a05338c14_----express.png.b02d38aa2b9e2797b00aa37f0cff0b4a.png" /></p>

<p>
	لقد امتلكنا الآن بعض المفاهيم الأساسية عن عمل TypeScript وعن كيفية استخدامها في إنشاء المشاريع الصغيرة، وأصبحنا قادرين على تنفيذ أشياء مفيدة فعلًا. سنبدأ إذًا بإنشاء مشروع جديد ذو استخدامات أكثر واقعية.
</p>

<p>
	سيكون التغيير الرئيسي في هذا القسم عدم استخدام ts-node. وعلى الرغم من أنها أداة مفيدة وتساعدك في الانطلاق، إلا أن استخدام المصرِّف الرسمي للغة هو الخيار المفضل، وخاصة على المدى الطويل لأعمالك. يأتي هذا المصرِّف مع الحزمة typescript، حيث يولّد ويحزم ملفات JavaScript انطلاقًا من ملفات "ts." وبذلك لن تحتوي نسخة الإنتاج بعد ذلك شيفرات TypeScript. وهذا ما نحتاجه فعلًا لأن TypeScript غير قابلة للتنفيذ على المتصفح أو على Node.
</p>

<h2>
	إعداد المشروع
</h2>

<p>
	سننشئ مشروعًا من أجل Ilari الذي يحب وضع خطط لرحلات جوية قصيرة، لكنه يعاني من ذكريات مزعجة متعلقة بهذه الرحلات. سيكون هو نفسه من سيكتب شيفرة التطبيق فلن يحتاج إلى واجهة مستخدم، لكنه يرغب باستعمال طلبات HTTP ويبقى خياراته مفتوحة في إضافة واجهة مستخدم مبنية على تقنيات الويب لاحقًا.
</p>

<p>
	لنبدأ بإنشاء أول مشروع واقعي لنا بعنوان Ilari flight diaries. وسنثبت كالعادة حزمة typescript باستخدام الأمر <code>npm init</code> ومن ثم <code>npm install typescript</code>.
</p>

<p>
	يساعدنا مصرِّف TypeScript الأصلي tsc في تهيئة المشروع من خلال الأمر <code>tsc --init</code>. لكن علينا أولًا أن نضيف الأمر tsc إلى قائمة السكربتات القابلة للتنفيذ داخل الملف package.json (إلا إن كنت قد ثبتَّ TypeScript لكافة المشاريع). وحتى لو ثبتّها لكافة المشاريع لابد من إدراجها كاعتمادية تطوير في مشروعك.
</p>

<p>
	سيكون سكربت npm الذي سينفذ الأمر tsc كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_6" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"tsc"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"tsc"</span><span class="pun">,</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يضاف الأمر tsc غالبًا لاستخدامه في سكربتات تنفذ سكربتات أخرى، وبالتالي من الشائع رؤية إعداداته ضمن المشروع بهذا الشكل.
</p>

<p>
	سنهيئ الآن إعدادات الملف tsconfig.json بتنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7877_7" style="">
<span class="pln"> npm run tsc </span><span class="pun">--</span><span class="pln"> </span><span class="pun">--</span><span class="pln">init</span></pre>

<p>
	<strong>لاحظ</strong> وجود المحرفين "--" قبل الوسيط الفعلي init. يُفسَّر الوسيط الذي يقع قبل "--" كأوامر npm والذي يقع بعدها كأوامر تُنفَّذ من قبل السكربت.
</p>

<p>
	ينتج عن تنفيذ الأمر السابق الملف tsconfig.ts الذي يضم قائمة طويلة بكل أوامر التهيئة التي يمكن ضبطها. وسترى أن قلة منها فقط لم تُسبق بعلامة التعليق. ستفيدك دراسة هذا الملف في إيجاد بعض تعليمات التهيئة التي قد تحتاجها. يمكنك أيضًا ترك الأسطر التي تبدأ بعلامة التعليق في الملف، فلربما قررت لاحقًا توسيع إعدادات التهيئة الخاصة بمشروعك.
</p>

<p>
	إن كل ما نحتاج إليه حاليًا من إعدادات هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_8" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ES6"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"outDir"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"./build/"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"module"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"commonjs"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strict"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedLocals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedParameters"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noImplicitReturns"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noFallthroughCasesInSwitch"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"esModuleInterop"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنعرّج على الإعدادات واحدًا تلو الآخر:
</p>

<ul>
<li>
		target: سيخبر المصرِّف عن نسخة ECMAScript التي سيستعملها لتوليد ملفات JavaScript. ولاحظ أن القيمة التي يأخذها هي ES6 التي تدعمها معظم المتصفحات، وهي خيار جيد وآمن.
	</li>
	<li>
		outDir: يحدد المجلد الذي سيحوي الشيفرة المصرِّفة.
	</li>
	<li>
		modules: يخبر المصرِّف أننا سنستخدم وحدات commonjs في الشيفرة المصرِّفة. وهذا يعني أننا نستطيع استخدام <code>require</code> بدلًا من <code>import</code> وهذا الأمر غير مدعوم في النسخ الأقدم من Node مثل النسخة 10.
	</li>
	<li>
		strict: وهو في الواقع اختصار لعدة خيارات منفصلة توجه استخدام ميزات TypeScript بطريقة أكثر تشددًا (يمكنك أن تجد تفاصيل بقية الخيارات في <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.staging-typescript.org/tsconfig#strict" rel="external nofollow">توثيق tsconfig</a>، كما ينصح التوثيق باستخدام strict دائمًا) هي:
		<ul>
<li>
				<a data-ss1621336271="1" data-ss1621337026="1" href="https://www.staging-typescript.org/tsconfig#noImplicitAny" rel="external nofollow">noImplicitAny</a>: يكون الخيار المألوف بالنسبة لنا هو الأكثر أهمية. ويمنع هذا الخيار تضمين النوع any (إعطاء قيمة ما النوع any)، والذي قد يحدث إن لم تحدد نوعًا لمعاملات دالة على سبيل المثال.
			</li>
			<li>
				noImplicitThis
			</li>
			<li>
				alwayesStrict
			</li>
			<li>
				strictBindCallApply
			</li>
			<li>
				strictNullChecks
			</li>
			<li>
				strictFunctionTypes
			</li>
			<li>
				strictpropertyIntialization
			</li>
		</ul>
</li>
	<li>
		noUnUsedLocals: يمنع وجود متغيرات محلية غير مستعملة.
	</li>
	<li>
		nofallThroughCasesInSwitch: ترمي خطأً إن احتوت الدالة على معامل لم يستعمل.
	</li>
	<li>
		esModuleInterop: تتأكد من وجود إحدى التعليمتين <code>return</code> أو <code>break</code> في نهاية الكتلة case، عند استخدام البنية switch case.
	</li>
	<li>
		ModuleInterop: تسمح بالتصريف بين وحدات commonjs و ES. يمكنك الاطلاع أكثر على هذا الإعداد في توثيق <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.staging-typescript.org/tsconfig#esModuleInterop" rel="external nofollow">tsconfig</a>
	</li>
</ul>
<p>
	وبما أننا أنهينا ضبط إعدادات التهيئة التي نريد، سنتابع العمل بتثبيت المكتبة express وتثبيت تعريفات الأنواع الموجودة ضمنها مستخدمين "types/express@". وبما أن المشروع واقعي، أي أنه سينمو مع الوقت، سنستخدم المدقق eslint من البداية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7877_10" style="">
<span class="pln">npm install express
npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev eslint </span><span class="lit">@types</span><span class="pun">/</span><span class="pln">express </span><span class="lit">@typescript</span><span class="pun">-</span><span class="pln">eslint</span><span class="pun">/</span><span class="pln">eslint</span><span class="pun">-</span><span class="pln">plugin </span><span class="lit">@typescript</span><span class="pun">-</span><span class="pln">eslint</span><span class="pun">/</span><span class="pln">parser</span></pre>

<p>
	ستبدو محتويات الملف package.json مشابهة للتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_11" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ilaris-flight-diaries"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"1.0.0"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"main"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"index.ts"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"tsc"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"tsc"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"test"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"echo \"Error: no test specified\" &amp;&amp; exit 1"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"author"</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"license"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ISC"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"dependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"express"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^4.17.1"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"devDependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@types/express"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^4.17.2"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@typescript-eslint/eslint-plugin"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^2.17.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@typescript-eslint/parser"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^2.17.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"eslint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^6.8.0"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"typescript"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^3.7.5"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	كما سننشئ ملف تهيئة المدقق ذو اللاحقة eslintrc ونزوده بالمحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_13" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">"eslint:recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:@typescript-eslint/recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:@typescript-eslint/recommended-requiring-type-checking"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"@typescript-eslint"</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"env"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"browser"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"es6"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@typescript-eslint/semi"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"error"</span><span class="pun">],</span><span class="pln">
    </span><span class="str">"@typescript-eslint/explicit-function-return-type"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@typescript-eslint/no-unused-vars"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
        </span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"argsIgnorePattern"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^_"</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">],</span><span class="pln">
     </span><span class="str">"@typescript-eslint/no-explicit-any"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"no-case-declarations"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"parser"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"@typescript-eslint/parser"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"parserOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"project"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"./tsconfig.json"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنتابع الآن العمل بإعداد بيئة التطوير، وسنصبح بعد ذلك جاهزين لكتابة الشيفرة الفعلية. هناك خيارات عدة لإجراء ذلك. فقد نستخدم المكتبة nodemon مع ts-node، لكن وكما رأينا سابقًا فالمكتبة ts-node-dev تؤمن الوظائف نفسها، لذا سنستمر في استخدامها:
</p>

<pre class="ipsCode">
npm install --save-dev ts-node-dev
</pre>

<p>
	سنعرّف بعض سكربتات npm:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_15" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"tsc"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"tsc"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node-dev index.ts"</span><span class="pun">,</span><span class="pln">    </span><span class="str">"lint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint --ext .ts ."</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هنالك الكثير لتفعله قبل البدء بكتابة الشيفرة. فعندما تعمل على مشروع حقيقي، سيفيدك الإعداد المتأني لبيئة التطوير إلى حد كبير. خذ وقتك في ضبط إعدادات بيئة العمل لك ولفريقك، وسترى أن كل شيء سيسير بسلاسة على المدى الطويل.
</p>

<h2>
	لنبدأ بكتابة الشيفرة
</h2>

<p>
	سنبدأ كتابة الشيفرة بإنشاء وصلة تخديم endpoint لتفقد الخادم، لكي نضمن أن كل شيء يعمل بالشكل الصحيح.
</p>

<p>
	فيما يلي محتوى الملف index.ts:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_17" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">();</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">());</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pun">;</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/ping'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'someone pinged here'</span><span class="pun">);</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'pong'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	لو نفذنا الآن الأمر <code>npm run dev</code> سنرى أن الطلب إلى العنوان <a data-ss1621336271="1" data-ss1621337026="1" href="http://localhost:3000/ping%D8%8C" ipsnoembed="true" rel="external nofollow">http://localhost:3000/ping،</a> سيعيد الاستجابة pong، وبالتالي فتهيئة المشروع قد أنجزت بالشكل الصحيح.
</p>

<p>
	سيعمل التطبيق بعد تنفيذ الأمر السابق في وضع التطوير. وهذا الوضع لن يكون مناسبًا أبدًا عند الانتقال لاحقًا إلى وضع الإنتاج.
</p>

<p>
	لنحاول إنجاز نسخة إنتاج بتشغيل مصرِّف TypeScript. وبما أننا حددنا قيمةً للإعداد outDir في الملف package.json، فلا شيء بقي لنفعله سوى تنفيذ السكربت باستخدام الأمر <code>npm run tsc</code>.
</p>

<p>
	ستكون النتيجة نسخة إنتاج مكتوبة بلغة JavaScript صرفة، لواجهة express الخلفية ضمن المجلد build.
</p>

<p>
	سيفسر المدقق eslint حاليًًا الملفات ويضعها ضمن المجلد build نفسه. ولا نرغب بالطبع أن يحدث هذا، فمن المفترض أن تكون الشيفرة الموجودة في هذا المجلد ناتجة عن المصرِّف فقط. يمكن منع ذلك بإنشاء ملف تجاهل لاحقته "eslintignore." يضم قائمة بالمحتوى الذي نريد من المدقق أن يتجاهله، كما هي الحال مع git وgitignore.
</p>

<p>
	لنضف سكربت npm لتشغيل التطبيق في وضع الإنتاج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_19" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"tsc"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"tsc"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node-dev index.ts"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"lint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint --ext .ts ."</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"node build/index.js"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وبتشغيل التطبيق باستخدام الأمر <code>npm start</code>، نتأكد أن نسخة الانتاج ستعمل أيضًا بشكل صحيح.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67118" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/express_backend_works_01.png.70fafd5b85ae5352fc58d29de44f3f96.png" rel=""><img alt="express_backend_works_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67118" data-unique="kehl64qjc" src="https://academy.hsoub.com/uploads/monthly_2021_05/express_backend_works_01.png.70fafd5b85ae5352fc58d29de44f3f96.png"></a>
</p>

<p>
	لدينا الآن بيئة تطوير تعمل بالحد الأدنى. وبمساعدة المصرِّف والمدقق eslint سنضمن أن تبقى الشيفرة بمستوًى جيد. وبناء على ما سبق سنتمكن من إنشاء تطبيق قابل للنشر لاحقًا كنسخ إنتاج.
</p>

<h2>
	التمرينان 9.8 - 9.9
</h2>

<h3>
	قبل أن تبدأ بالحل
</h3>

<p>
	ستطوّر خلال مجموعة التمارين هذه واجهة خلفية لمشروع جاهز يدعى Patientor. والمشروع عبارة عن تطبيق سجلات طبية بسيط يستخدمه الأطباء الذين يشخصون الأمراض ويسجلون المعلومات الصحية لمرضاهم.
</p>

<p>
	بُنيت <a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/fullstack-hy2020/patientor" rel="external nofollow">الواجهة الأمامية</a> مسبقًا من قبل خبراء خارجيين، ومهمتك أن تطور واجهة خلفية تدعم الشيفرة الموجودة.
</p>

<h3>
	9.8 الواجهة الخلفية لتطبيق إدارة المرضى: الخطوة 1
</h3>

<p>
	هيئ المشروع الذي ستستخدمه الواجهة الأمامية. ثم هيئ المدقق eslint والملف tsconfig بنفس إعدادات التهيئة التي استخدمناها سابقًا. عرِّف وصلة تخديم تستجيب لطلبات HTTP-GET المرسلة إلى الوجهة ping/.
</p>

<p>
	ينبغي أن يعمل المشروع باستخدام سكربتات npm في وضع التطوير، وكشيفرة مصرّفة في وضع الإنتاج.
</p>

<h3>
	9.9 الواجهة الخلفية لتطبيق إدارة المرضى: الخطوة 2
</h3>

<p>
	انسخ المشروع <a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/fullstack-hy2020/patientor" rel="external nofollow">patientor</a>. شغل بعد ذلك التطبيق مستعينًا بالملف README.md. يجب أن تعمل الواجهة الأمامية دون حاجة لوجود واجهة خلفية وظيفية.
</p>

<p>
	تأكد من استجابة الواجهة الخلفية إلى طلب التحقق من الخادم ping الذي ترسله الواجهة الأمامية. وتحقق من أداة التطوير للتأكد من سلامة عملها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67123" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step2_ping_02.png.13f60d858d64a8e1fc7b7893ec99fe58.png" rel=""><img alt="patientor_step2_ping_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67123" data-unique="v6nc4zjio" src="https://academy.hsoub.com/uploads/monthly_2021_05/patientor_step2_ping_02.png.13f60d858d64a8e1fc7b7893ec99fe58.png"></a>
</p>

<p>
	من الجيد أن تلقي نظرة على النافذة console في طرفية التطوير. وإن أخفق شيء ما، استعن بمعلومات القسم الثالث المتعلقة بحل هذه المشكلة.
</p>

<h2>
	كتابة شيفرة وظائف الواجهة الخلفية
</h2>

<p>
	لنبدأ بالأساسيات. يريد Ilari أن يكون قادرًا على مراجعة ما اختبره خلال رحلاته الجوية. إذ يريد تخزين مدخلات في مذكراته تتضمن المعلومات التالية:
</p>

<ul>
<li>
		تاريخ المُدخل
	</li>
	<li>
		حالة الطقس (جيد، رياح، ماطر، عاصف)
	</li>
	<li>
		مدى الرؤية (جيد، ضعيف)
	</li>
	<li>
		نص يفصِّل تجربته ضمن الرحلة.
	</li>
</ul>
<p>
	حصلنا على عينة من المعلومات التي سنستخدمها كأساس نبني عليه. خُزّنت المعلومات بصيغة JSON ويمكن الحصول عليها من <a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/fullstack-hy2020/misc/blob/master/diaryentries.json" rel="external nofollow">GitHub</a>.
</p>

<p>
	تبدو البيانات على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_21" style="">
<span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2017-01-01"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"weather"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"rainy"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"visibility"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"poor"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"comment"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pretty scary flight, I'm glad I'm alive"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2017-04-01"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"weather"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"sunny"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"visibility"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"good"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"comment"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Everything went better than expected, I'm learning much"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">]</span></pre>

<p>
	لننشئ وصلة تخديم تعيد كل مدخلات مذكرة الرحلات.
</p>

<p>
	علينا في البداية إتخاذ بعض القرارات المتعلقة بطريقة هيكلة الشيفرة المصدرية. فمن الأفضل في حالتنا وضع الشيفرة بأكملها في مجلد واحد باسم src، وهكذا لن تختلط ملفات الشيفرة مع ملفات التهيئة. إذًا سننقل الملف إلى هذا المجلد ونجري التعديلات اللازمة على سكربت npm.
</p>

<p>
	سنضع أيضًا وحدات المتحكمات بالمسار <a data-ss1621336271="1" data-ss1621337026="1" href="https://fullstackopen.com/en/part4/structure_of_backend_application_introduction_to_testing" rel="external nofollow">routers</a> المسؤولة عن التعامل مع موارد محددة كمدخلات المذكرات، ضمن المجلد src/routes. يختلف ما فعلناه قليلًا عن المقاربة التي اتبعناها في القسم 4 حيث وضعنا المتحكمات في المجلد src/controllers.
</p>

<p>
	ستجد شيفرة المتحكم الذي يتعامل مع جميع وصلات تخديم المرتبطة بالمذكّرات في الملف "src/routes/diaries.ts" الذي يحتوي الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_23" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">.</span><span class="typ">Router</span><span class="pun">();</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'Fetching all diaries!'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'Saving a diary!'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> router</span><span class="pun">;</span></pre>

<p>
	سنوجّه كل الطلبات التي تبدأ بالعنوان api/diaries/ إلى متحكم المسار المحدد في الملف index.ts
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_25" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> diaryRouter from </span><span class="str">'./routes/diaries'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">();</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">());</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pun">;</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/ping'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'someone pinged here'</span><span class="pun">);</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'pong'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/diaries'</span><span class="pun">,</span><span class="pln"> diaryRouter</span><span class="pun">);</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	وهكذا لو أرسلنا طلبًا إلى العنوان <a data-ss1621336271="1" data-ss1621337026="1" href="http://localhost:3000/api/diaries" ipsnoembed="true" rel="external nofollow">http://localhost:3000/api/diaries</a> فمن المفترض أن نرى الرسالة Fetching all diaries.
</p>

<p>
	علينا تاليًا البدء بتقديم البيانات الأساسية (عينة المذكّرات) انطلاقًا من التطبيق. إذ سنحضر البيانات ونخزنها في الملف data/diaries.json.
</p>

<p>
	لن نكتب الشيفرة التي تغير البيانات الفعلية في ملف المتحكم بالمسار، بل سننشئ خدمة تهتم بهذا الأمر. ويعتبر فصل "منطق العمل" عن شيفرة متحكمات المسار ضمن وحدات منفصلة أمرًا شائعًا، وتدعى في أغلب الأحيان "خدمات". ويعود أصل هذه التسمية إلى مفهوم التصميم المقاد بالمجال <a data-ss1621336271="1" data-ss1621337026="1" href="https://en.wikipedia.org/wiki/Domain-driven_design" rel="external nofollow">Domain driven design</a>، ومن ثم جعله إطار العمل <a data-ss1621336271="1" data-ss1621337026="1" href="https://spring.io/" rel="external nofollow">Spring</a> أكثر شعبية.
</p>

<p>
	لننشئ مجلدًا للخدمات يدعى src/services، ونضع الملف diaryService.ts فيه. يحتوي الملف على دالتين لإحضار وتخزين مُدخلات المذكرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_27" style="">
<span class="kwd">import</span><span class="pln"> diaryData from </span><span class="str">'../../data/diaries.json'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> diaryData</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  addEntry
</span><span class="pun">};</span></pre>

<p>
	لكن سنلاحظ خللًا ما:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67112" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/diaries_service_error_03.png.aa876ef3653adecd580b7273743120ee.png" rel=""><img alt="diaries_service_error_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67112" data-unique="lwn9nqsy9" src="https://academy.hsoub.com/uploads/monthly_2021_05/diaries_service_error_03.png.aa876ef3653adecd580b7273743120ee.png"></a>
</p>

<p>
	يخبرنا المحرر أننا قد نحتاج إلى استعمال الإعداد resolveJsonModule في ملف التهيئة tsconfig. سنضيفه إذًا إلى قائمة الإعدادات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_29" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ES6"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"outDir"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"./build/"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"module"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"commonjs"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strict"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedLocals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedParameters"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noImplicitReturns"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noFallthroughCasesInSwitch"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"esModuleInterop"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"resolveJsonModule"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا ستختفي المشكلة:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ملاحظة: لأسباب معينة قد تخبرك بيئة التطوير VSCode بأنها لا تستطيع إيجاد الملف data/diaries.json/../.. من الخدمة على الرغم من وجوده. هذه ثغرة في المحرر، ويختفي الخطأ بمجرد إعادة تشغيله.
	</p>
</blockquote>

<p>
	وجدنا في وقت سابق كيف يمكن للمصرِّف أن يقرر نوع المتغير بناء على القيمة التي أسندت إليه. وبالمثل يمكن للمصرِّف تفسير مجموعات كبيرة من البيانات تتضمن كائنات ومصفوفات. وبناء على ذلك يمكن للمصرِّف أن يحذرنا عندما نحاول أن نفعل شيئًا قد يعتبره مريبًا باستخدام بيانات JSON التي نعالجها. فلو كنا نتعامل على سبيل المثال مع مصفوفة من كائنات محددة النوع، وحاولنا إضافة كائن لا يمتلك كل حقول كائنات المصفوفة أو خللًا في نوع الحقل (number بدل string مثلًا)، سيحذرنا المصرِّف مباشرة.
</p>

<p>
	وعلى الرغم من فائدة المصرِّف في التحقق من أننا لم نفعل شيئًا خاطئًا، فتحديد أنواع البيانات بأنفسنا هو الخيار الأكثر أمانًا.
</p>

<p>
	ما لدينا حاليًا، هو تطبيق express باستخدام TypeScript يعمل بشكل محدود، لكن لا وجود لأية أنواع في شيفرته. وطالما أننا على دراية بأنواع البيانات التي سنستقبلها في حقلي <code>weather</code>، و<code>visibility</code>، فلا سبب سيدفعنا لإدراج نوعيهما في الشيفرة.
</p>

<p>
	لننشئ ملفًا للأنواع يدعى types.ts، وسنعرّف ضمنه كل الأنواع التي سنستخدمها في المشروع.
</p>

<p>
	أولًا سنعرف نوعين لقيم <code>weather</code>، و<code>visibility</code> باستخدام نوع موّحد <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types" rel="external nofollow">union type</a> للقيم النصية التي يمكن أن يأخذها الحقلين:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_31" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'sunny'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'rainy'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'cloudy'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'windy'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'stormy'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> type </span><span class="typ">Visibility</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'great'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'good'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'ok'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'poor'</span><span class="pun">;</span></pre>

<p>
	سنتابع بإنشاء واجهة نوع <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/interfaces.html" rel="external nofollow">interface</a> باسم DiaryEntry:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_33" style="">
<span class="kwd">export</span><span class="pln"> interface </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  weather</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">;</span><span class="pln">
  visibility</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">;</span><span class="pln">
  comment</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وسنحاول تحديد نوع لبيانات JSON المُدرجة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_35" style="">
<span class="kwd">import</span><span class="pln"> diaryData from </span><span class="str">'../../data/diaries.json'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> diaries</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> diaryData</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">;};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  addEntry
</span><span class="pun">};</span></pre>

<p>
	ولأننا صرحنا مسبقا عن القيم، فإسناد نوع لها سيوّلد خطأً:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67120" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/json_data_type_assign_error_04.png.6b6edac034de149eccb6ae3e144575ae.png" rel=""><img alt="json_data_type_assign_error_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67120" data-unique="iatxes0ly" src="https://academy.hsoub.com/uploads/monthly_2021_05/json_data_type_assign_error_04.png.6b6edac034de149eccb6ae3e144575ae.png"></a>
</p>

<p>
	تُظهر نهاية رسالة الخطأ المشكلة: الحقل غير ملائم. فقد حددنا نوعه في واجهة النوع على أنه DiaryEntry، لكن المصرِّف استدل من القيمة المسندة إليه أنه من النوع string.
</p>

<p>
	يمكن حل المشكلة بتأكيد النوع <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions" rel="external nofollow">type assertion</a>. ولا ينبغي فعل ذلك إلا عندما نعلم قطعًا مالذي نفعله. فلو أكدنا أن نوع المتغير <code>diaryData</code> هو DiaryEntry باستخدام التعليمة <code>as</code> سيعمل كل شيء على مايرام.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_37" style="">
<span class="kwd">import</span><span class="pln"> diaryData from </span><span class="str">'../../data/entries.json'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> diaries</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> diaryData as </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  addEntry
</span><span class="pun">};</span></pre>

<p>
	لا تستخدم أسلوب تأكيد النوع إلا في غياب أية طرق أخرى للمتابعة. فتأكيد نوع غير مناسب سيسبب أخطاءً مزعجة في زمن التشغيل. على الرغم من أن المصرِّف سيثق بك عندما تستخدم <code>as</code>، لكن بعملك هذا لن تكون قد سخرت الإمكانيات الكاملة للغة TypeScript بل اعتمدت على المبرمج لضمان عمل الشيفرة.
</p>

<p>
	من الممكن في حالتنا تغيير الطريقة التي نصدّر بها البيانات، وذلك بإعطائها نوعًا. وبما أننا لا نستطيع استخدام الأنواع داخل ملف JSON لابد من تحويله إلى ملف TS الذي يصدِّر البيانات على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_39" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../src/types"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> diaryEntries</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2017-01-01"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"weather"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"rainy"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"visibility"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"poor"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"comment"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pretty scary flight, I'm glad I'm alive"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">];</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> diaryEntries</span><span class="pun">;</span></pre>

<p>
	وهكذا سيفسر المصرِّف المصفوفة عند إدراجها بشكل صحيح، وسيفهم نوع الحقلين <code>weather</code> و<code>visibility</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_41" style="">
<span class="kwd">import</span><span class="pln"> diaries from </span><span class="str">'../../data/diaries'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  addEntry
</span><span class="pun">};</span></pre>

<p>
	لو أردت أن تُخزّن مُدخلًا ما باستثناء حقل محدد، يمكنك ضبط نوع هذا الحقل <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/interfaces.html#optional-properties" rel="external nofollow">كحقل اختياري</a> بإضافة "؟" إلى تعريف النوع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_43" style="">
<span class="kwd">export</span><span class="pln"> interface </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
  weather</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">;</span><span class="pln">
  visibility</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">;</span><span class="pln">
  comment</span><span class="pun">?:</span><span class="pln"> string</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	وحدات Node وJSON
</h2>

<p>
	من المهم أن تنتبه إلى مشكلة قد تظهر عند استخدام الخيار resolveJsonModule في الملف tsconfig:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_45" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
    </span><span class="str">"resolveJsonModule"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	فبناء على توثيق node المتعلق <a data-ss1621336271="1" data-ss1621337026="1" href="https://nodejs.org/api/modules.html#modules_file_modules" rel="external nofollow">بملفات الوحدات</a>، ستحاول node أن تنفّذ الوحدات وفق ترتيب اللاحقات كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_47" style="">
<span class="pln"> </span><span class="pun">[</span><span class="str">"js"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"json"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"node"</span><span class="pun">]</span></pre>

<p>
	وبالإضافة إلى ذلك ستوسِّع المكتبتان ts-node وts-node-dev قائمة اللاحقات لتصبح كالتالي:
</p>

<pre class="ipsCode">
 ["js", "json", "node", "ts", "tsx"]
</pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			ملاحظة: إن صلاحية استخدام ملفات باللاحقات js. و json. وnode على أساس وحدات في TypeScript، سيعتمد على إعدادات تهيئة بيئة التطوير بما في ذلك خيارات tsconfig، مثل: allowJs وresolveJsonModule.
		</p>
	</div>
</blockquote>

<p>
	لنتأمل الهيكيلة التالية لمجلد يحتوي على ملفات:
</p>

<pre class="ipsCode">
  ├── myModule.json
  └── myModule.ts
</pre>

<p>
	إن ضبطنا الخيار resolveJsonModule على القيمة true في TypeScript، سيصبح الملف myModule.json وحدة node صالحة للاستخدام. لنتخيل الآن السيناريو الذي نرغب فيه باستخدام الملف myModule.ts:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_49" style="">
<span class="kwd">import</span><span class="pln"> myModule from </span><span class="str">"./myModule"</span><span class="pun">;</span></pre>

<p>
	بالنظر إلى ترتيب لاحقات الوحدات في node:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_51" style="">
<span class="pln"> </span><span class="pun">[</span><span class="str">"js"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"json"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"node"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"ts"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"tsx"</span><span class="pun">]</span></pre>

<p>
	سنلاحظ أن الأولوية ستكون للملف ذو اللاحقة "json." على الملف ذو اللاحقة "ts."، وبالتالي سيُدرج الملف myModule.json بدلًا من الملف myModule.ts.
</p>

<p>
	ولكي نتجنب هذه الثغرة التي ستضيع الكثير من الوقت، يفضل أن نسمي الملفات التي تحمل لاحقة تفهمها node بأسماء مختلفة.
</p>

<h2>
	الأنواع الخدمية
</h2>

<p>
	قد نحتاج أحيانًا إلى إجراء تعديلات محددة على نوع. فلنفترض مثلًا وجود صفحة لعرض قائمة من البيانات التي يعتبر بعضها بيانات حساسة وأخرى غير حساسة. ونريد أن نضمن عدم عرض البيانات الحساسة. يمكننا اختيار الحقول التي نريدها من نوع محدد، عن طريق استخدام أحد الأنواع الخدمية Utility type ويدعى <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/utility-types.html#picktk" rel="external nofollow">Pick</a>.
</p>

<p>
	ينبغي علينا في مشروعنا أن نفترض أن Ilari يريد إظهار قائمة بالمذكرات دون أن يُظهر حقل التعليقات، فقد يكتب شيئًا لايريد إظهاره لأحد، وخاصة في الرحلات التي أفزعته بشدة.
</p>

<p>
	يسمح النوع الخدمي Pick أن نختار ما نريد استخدامه من حقول نوع محدد. ويستخدم هذا النوع لإنشاء نوع جديد تمامًا أو لإعلام الدالة ما يجب أن تعيده في زمن التشغيل. فالأنواع الخدمية هي صنف خاص من أدوات إنشاء الأنواع، لكن يمكن استخدامها كما نستخدم أي نوع آخر.
</p>

<p>
	ولكي ننشئ نسخة خاضعة للرقابة من النوع DiaryEntry، سنستخدم Pick عند تعريف الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_53" style="">
<span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln">
  </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="typ">Pick</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'date'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'weather'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'visibility'</span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	سيتوقع المصرِّف أن تعيد الدالة مصفوفة قيم من النوع DiaryEntry المعدّل والذي يتضمن الحقول الأربعة المختارة فقط.
</p>

<p>
	وطالما أن النوع Pick سيتطلب أن يكون النوع الذي سيعدّله معطًى <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/generics.html#working-with-generic-type-variables" rel="external nofollow">كنوع متغير</a>، كما هو حال المصفوفة، سيكون لدينا نوعين متغيرين ومتداخلين، وستبدو العبارة غريبة بعض الشيء. يمكن تحسين القدرة على قراءة الشيفرة باستخدام العبارة <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#array" rel="external nofollow">البديلة</a> للمصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_55" style="">
<span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln">
  </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Pick</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'date'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'weather'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'visibility'</span><span class="pun">&gt;[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span></pre>

<p>
	سنحتاج في حالتنا إلى استثناء حقل واحد، لذلك من الأفضل أن نستخدم النوع الخدمي <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/utility-types.html#omittk" rel="external nofollow">Omit</a> والذي يحدد الحقول التي يجب استبعادها من نوع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_57" style="">
<span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">Omit</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="str">'comment'</span><span class="pun">&gt;[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وكطريقة أخرى، يمكن التصريح عن نوع جديد NonSensitiveDiaryEntry كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_59" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Omit</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="str">'comment'</span><span class="pun">&gt;;</span></pre>

<p>
	ستصبح الشيفرة الآن على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_61" style="">
<span class="kwd">import</span><span class="pln"> diaries from </span><span class="str">'../../data/diaries'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  addEntry</span><span class="pun">,</span><span class="pln">
  getNonSensitiveEntries</span><span class="pun">};</span></pre>

<p>
	هنالك شيء واحد سيسبب القلق في تطبيقنا. ستعيد الدالة <code>getNonSensitiveEntries</code> كامل حقول المُدخلات عند تنفيذها، ولن يعطينا المصرِّف أية أخطاء على الرغم من تحديد نوع المعطيات المعادة.
</p>

<p>
	يحدث هذا لسبب بسيط هو أن TypeScript <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/type-compatibility.html" rel="external nofollow">ستتحقق فقط</a> من وجود كل الحقول المطلوبة، ولن تمنع وجود حقول زائدة. فلن تمنع في حالتنا إعادة كائن من النوع [ ]DiaryEntry، لكن لو حاولنا الوصول إلى الحقل <code>comment</code> فلن نتمكن من ذلك، لأن TypeScript لا تراه على الرغم من وجوده.
</p>

<p>
	سيقود ذلك إلى سلوك غير مرغوب إن لم تكن مدركًا ما تفعله. فلو كنا سنعيد كل المُدخلات عند تنفيذ الدالة <code>getNonSensitiveEntries</code> إلى الواجهة الأمامية، ستكون النتيجة وصول قيمٍ لحقول لانريدها إلى المتصفح الذي أرسل الطلب، وهذا مخالف لتعريف نوع القيم المعادة.
</p>

<p>
	علينا إذًا استثناء تلك الحقول بأنفسنا، طالما أن TypeScript لا تعدّل البيانات الفعلية المعادة بل نوعها فقط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_63" style="">
<span class="kwd">import</span><span class="pln"> diaries from </span><span class="str">'../../data/entries.js'</span><span class="pln">

</span><span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> diaries
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">():</span><span class="pln"> </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pln"> </span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> diaries</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(({</span><span class="pln"> id</span><span class="pun">,</span><span class="pln"> date</span><span class="pun">,</span><span class="pln"> weather</span><span class="pun">,</span><span class="pln"> visibility </span><span class="pun">})</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">({</span><span class="pln">
        id</span><span class="pun">,</span><span class="pln">
        date</span><span class="pun">,</span><span class="pln">
        weather</span><span class="pun">,</span><span class="pln">
        visibility</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">}));};</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> addDiary </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  getNonSensitiveEntries</span><span class="pun">,</span><span class="pln">
  addDiary
</span><span class="pun">}</span></pre>

<p>
	فلو أردنا الآن إعادة هذه البيانات على أنها من النوع "DiaryEntry" كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_65" style="">
<span class="kwd">const</span><span class="pln"> getNonSensitiveEntries </span><span class="pun">=</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span></pre>

<p>
	سنحصل على الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67114" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/diaryentry_return_error_05.png.71c8d1e06e14dbdee7acbab6002190e0.png" rel=""><img alt="diaryentry_return_error_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67114" data-unique="mg98wc1mx" src="https://academy.hsoub.com/uploads/monthly_2021_05/diaryentry_return_error_05.png.71c8d1e06e14dbdee7acbab6002190e0.png"></a>
</p>

<p>
	سيقدم لنا السطر الأخير من الرسالة هذه المرة أيضًا فكرة الحل. لنتراجع عن هذا التعديل.
</p>

<p>
	تتضمن الأنواع الخدمية العديد من الوسائل المفيدة، وتستحق أن نقف عندها لبعض الوقت ونطلع على <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="external nofollow">توثيقها</a>.
</p>

<p>
	وأخيرًا يمكننا إكمال المسار الذي يعيد كل المُدخلات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_67" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> diaryService from </span><span class="str">'../services/diaryService'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> router </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">.</span><span class="typ">Router</span><span class="pun">();</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="pln">diaryService</span><span class="pun">.</span><span class="pln">getNonSensitiveEntries</span><span class="pun">());});</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">_req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'Saving a diary!'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> router</span><span class="pun">;</span></pre>

<p>
	وستكون الاستجابة كما نريدها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67113" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/diaries_without_comments_06.png.9d6bf564c1b30b0f348816ae1bd294d2.png" rel=""><img alt="diaries_without_comments_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67113" data-unique="8x9ughn71" src="https://academy.hsoub.com/uploads/monthly_2021_05/diaries_without_comments_06.png.9d6bf564c1b30b0f348816ae1bd294d2.png"></a>
</p>

<h2>
	التمرينان 9.10 -9.11
</h2>

<p>
	لن نستخدم في هذه التمارين قاعدة بيانات حقيقية في تطبيقنا، بل بيانات محضرة مسبقًا موجودة في الملفين <a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/fullstack-hy2020/misc/blob/master/diagnoses.json" rel="external nofollow">diagnoses.json</a> و<a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/fullstack-hy2020/misc/blob/master/patients.json" rel="external nofollow">patients.json</a>. نزِّل الملفين وخزنهما في مجلد يدعى data في مشروعك. ستجري التعديلات على البيانات في ذاكرة التشغيل فقط، فلا حاجة للكتابة على الملفين في هذا القسم.
</p>

<h3>
	9.10 واجهة خلفية لتطبيق إدارة المرضى: الخطوة 3
</h3>

<p>
	أنشئ النوع daiagnoses واستخدمه لإنشاء وصلة التخديم لإحضار كل تشخيصات المريض من خلال الطلب HTTP -GET. اختر هيكيلة مناسبة لشيفرتك عبر اختيار أسماء ملائمة للملفات والمجلدات.
</p>

<p>
	<strong>ملاحظة</strong>: قد يحتوي النوع daiagnoses على الحقل <code>latin</code> وقد لا يحتويه. ربما ستحتاج إلى استخدام <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/interfaces.html#optional-properties" rel="external nofollow">الخصائص الاختيارية</a> عند تعريف النوع.
</p>

<h3>
	9.11 واجهة خلفية لتطبيق إدارة المرضى: الخطوة 4
</h3>

<p>
	أنشئ نوعًا للبيانات باسم Patient ثم أنشئ وصلة تخديم لطلبات GET على العنوان api/patients/ لتعيد بيانات كل المرضى إلى الواجهة الأمامية لكن دون الحقل <code>ssn</code>. استخدم <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="external nofollow">الأنواع الخدمية</a> للتأكد من أنك أعدت الحقول المطلوبة فقط.
</p>

<p>
	يمكنك في هذا التمرين افتراض نوع الحقل <code>gender</code> على أنه string.
</p>

<p>
	جرب وصلة التخديم من خلال المتصفح، وتأكد أن الحقل <code>ssn</code> غير موجود في بيانات الاستجابة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67115" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/endpoint_test_07.png.5b525bbe63306243aea231c6af82fa42.png" rel=""><img alt="endpoint_test_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67115" data-unique="z40g4265a" src="https://academy.hsoub.com/uploads/monthly_2021_05/endpoint_test_07.png.5b525bbe63306243aea231c6af82fa42.png"></a>
</p>

<p>
	تأكد من عرض الواجهة الأمامية لقائمة المرضى بعد إنشائك لوصلة التخديم:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67119" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/frontend_shows_patients_list_08.png.b2f8150397b8ace7b10ad7fc5ac9eda4.png" rel=""><img alt="frontend_shows_patients_list_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67119" data-unique="xv7o0ziy0" src="https://academy.hsoub.com/uploads/monthly_2021_05/frontend_shows_patients_list_08.png.b2f8150397b8ace7b10ad7fc5ac9eda4.png"></a>
</p>

<h2>
	منع الحصول على نتيجة غير محددة عرضيا
</h2>

<p>
	سنوسع الواجهة الخلفية لدعم وظيفة الحصول على مُدخل محدد من خلال الطلبGET إلى العنوان api/diaries/:id.
</p>

<p>
	سنوسّع الخدمة DiaryService بإنشاء الدالة <code>findById</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_69" style="">
<span class="com">// ...</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> findById </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">):</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> entry </span><span class="pun">=</span><span class="pln"> diaries</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">d </span><span class="pun">=&gt;</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> entry</span><span class="pun">;};</span><span class="pln">
</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  getEntries</span><span class="pun">,</span><span class="pln">
  getNonSensitiveEntries</span><span class="pun">,</span><span class="pln">
  addDiary</span><span class="pun">,</span><span class="pln">
  findById</span><span class="pun">}</span></pre>

<p>
	مرة أخرى سيواجهنا الخطأ التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67116" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/entries_id_may_not_found_09.png.2eed61b04d097bab4b50aa5f0255baf7.png" rel=""><img alt="entries_id_may_not_found_09.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67116" data-unique="2vwc5s2ex" src="https://academy.hsoub.com/uploads/monthly_2021_05/entries_id_may_not_found_09.png.2eed61b04d097bab4b50aa5f0255baf7.png"></a>
</p>

<p>
	تظهر المشكلة لأن وجود مُدخل بمعرِّف id محدد غير مضمون. من الجيد أننا أدركنا هذه المشكلة في مرحلة التصريف. فلو لم نستخدم TypeScript لما جرى تحذيرنا من قبل المصرِّف، وقد نعيد في السيناريو الأسوء كائنًا غير محدد بدلًا من تنبيه المستخدم أنه لاتوجد مُدخلات بهذا المعرِّف.
</p>

<p>
	نحتاج قبل كل شيء في حالات كهذه إلى اتخاذ قرار بشأن القيمة المعادة إن لم نجد الكائن المطلوب، وكيفية معالجة هذه الحالة. يعيد تابع المصفوفات <code>find</code> كائنًا غير محدد إن لم يجد الكائن المطلوب، ولا مشكلة في ذلك. إذ يمكن حل مشكلتنا بتحدبد نوع للقيمة المعادة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_71" style="">
<span class="kwd">const</span><span class="pln"> findById </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">id</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">):</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="kwd">undefined</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> entry </span><span class="pun">=</span><span class="pln"> diaries</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">d </span><span class="pun">=&gt;</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">id </span><span class="pun">===</span><span class="pln"> id</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> entry</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وسنستخدم معالج المسار التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_73" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> diaryService from </span><span class="str">'../services/diaryService'</span><span class="pln">

router</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/:id'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> diary </span><span class="pun">=</span><span class="pln"> diaryService</span><span class="pun">.</span><span class="pln">findById</span><span class="pun">(</span><span class="typ">Number</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">params</span><span class="pun">.</span><span class="pln">id</span><span class="pun">));</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">diary</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="pln">diary</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">sendStatus</span><span class="pun">(</span><span class="lit">404</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> router</span><span class="pun">;</span></pre>

<h2>
	إضافة مذكرة جديدة
</h2>

<p>
	لنبدأ بإنشاء وصلة تخديم لطلبات HTTP-POST وذلك لإضافة مّدخلات جديدة إلى المذكرات. ينبغي أن تحمل المدخلات النوع ذاته للبيانات المطلوبة.
</p>

<p>
	تعالج الشيفرة التالية بيانات الاستجابة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_75" style="">
<span class="pln">router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> date</span><span class="pun">,</span><span class="pln"> weather</span><span class="pun">,</span><span class="pln"> visibility</span><span class="pun">,</span><span class="pln"> comment </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newDiaryEntry </span><span class="pun">=</span><span class="pln"> diaryService</span><span class="pun">.</span><span class="pln">addDiary</span><span class="pun">(</span><span class="pln">
    date</span><span class="pun">,</span><span class="pln">
    weather</span><span class="pun">,</span><span class="pln">
    visibility</span><span class="pun">,</span><span class="pln">
    comment</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">);</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">newDiaryEntry</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	وسيكون التابع الموافق في شيفرة الخدمة DiaryService كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_77" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Visibility</span><span class="pun">,</span><span class="pln">  </span><span class="typ">Weather</span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pun">;</span><span class="pln">


</span><span class="kwd">const</span><span class="pln"> addDiary </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln">
    weather</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Weather</span><span class="pun">,</span><span class="pln">
    visibility</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pun">,</span><span class="pln">
    comment</span><span class="pun">:</span><span class="pln"> string
  </span><span class="pun">):</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">const</span><span class="pln"> newDiaryEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">diaries</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">d </span><span class="pun">=&gt;</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    date</span><span class="pun">,</span><span class="pln">
    weather</span><span class="pun">,</span><span class="pln">
    visibility</span><span class="pun">,</span><span class="pln">
    comment</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  diaries</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">newDiaryEntry</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> newDiaryEntry</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	وكما ترى، سيغدو من الصعب قراءة الدالة <code>addDiary</code> نظرًا لكتابة كل الحقول كمعاملات منفصلة. وقد يكون من الأفضل لو أرسلنا البيانات ضمن كائن واحد إلى الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_79" style="">
<span class="pln">router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> date</span><span class="pun">,</span><span class="pln"> weather</span><span class="pun">,</span><span class="pln"> visibility</span><span class="pun">,</span><span class="pln"> comment </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newDiaryEntry </span><span class="pun">=</span><span class="pln"> diaryService</span><span class="pun">.</span><span class="pln">addDiary</span><span class="pun">({</span><span class="pln">
    date</span><span class="pun">,</span><span class="pln">
    weather</span><span class="pun">,</span><span class="pln">
    visibility</span><span class="pun">,</span><span class="pln">
    comment</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">});</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">newDiaryEntry</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	لكن ما نوع هذا الكائن؟ فهو ليس من النوع DiaryEntry تمامًا كونه يفتقد الحقل <code>id</code>. من الأفضل هنا لو أنشأنا نوعًا جديدًا باسم NewDiaryEntry للمُدخلات التي لم تُخزَّن بعد. لنعرّف هذا النوع في الملف types.ts مستخدمين النوع DiaryEntry مع النوع الخدمي <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/utility-types.html#omittk" rel="external nofollow">Omit</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_81" style="">
<span class="kwd">export</span><span class="pln"> type </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Omit</span><span class="pun">&lt;</span><span class="typ">DiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="str">'id'</span><span class="pun">&gt;;</span></pre>

<p>
	يمكننا الآن استخدام النوع الجديد في الخدمة DiaryService، بحيث يُفكَّك الكائن الجديد عند إنشاء مُدخل جديد من أجل تخزينه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_83" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="typ">NonSensitiveDiaryEntry</span><span class="pun">,</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'../types'</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ...</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> addDiary </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> entry</span><span class="pun">:</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">):</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newDiaryEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    id</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(...</span><span class="pln">diaries</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">d </span><span class="pun">=&gt;</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">id</span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="pun">...</span><span class="pln">entry
    </span><span class="pun">};</span><span class="pln">

  diaries</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">newDiaryEntry</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> newDiaryEntry</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	ستبدو الشيفرة أوضح الآن!
</p>

<p>
	ولتفسير البيانات المستقبلة، علينا تهيئة أداة JSON الوسطية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_85" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> diaryRouter from </span><span class="str">'./routes/diaries'</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">();</span><span class="pln">
app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="pln">express</span><span class="pun">.</span><span class="pln">json</span><span class="pun">());</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3000</span><span class="pun">;</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">use</span><span class="pun">(</span><span class="str">'/api/diaries'</span><span class="pun">,</span><span class="pln"> diaryRouter</span><span class="pun">);</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	أصبح التطبيق الآن جاهزًا لاستقبال طلبات HTTP-POST لإنشاء مُدخلات جديدة بالنوع الصحيح.
</p>

<h2>
	التأكد من الطلب
</h2>

<p>
	هناك الكثير من الأمور التي قد تسير بشكل خاطئ عند استقبال بيانات من مصدر خارجي. فلا يمكن أن تعمل التطبيقات بنفسها إلا نادرًا، وعلينا أن نقبل حقيقة أن البيانات التي نحصل عليها من خارج منظومة التطبيق غير موثوقة بشكل كامل. فلا يمكن أن تكون البيانات عند استقبالها من مصدر خارجي محددة النوع مسبقًا. وعلينا أن نقرر الأسلوب الذي سنتعامل به مع ضبابية هذه الحالة.
</p>

<p>
	تعالج express الموضوع بتأكيد النوع <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#any" rel="external nofollow">any</a> لكل حقول جسم الطلب. لن يكون هذا السلوك واضحًا للمصرِّف في حالتنا، لكن لو حاولنا إلقاء نظرة أقرب إلى المتغيرات، ومررنا مؤشر الفأرة فوق كل منها، سنجد أن نوع كل منها هو بالفعل any. وبالتالي لن يعترض المحرر أبدًا عندما نمرر هذه البيانات إلى الدالة <code>addDiary</code> كمعاملات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67122" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/oustside_data_typed_any_10.png.a1679bf69f4828bbb9ab2189383b6620.png" rel=""><img alt="oustside_data_typed_any_10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67122" data-unique="kjmv505vv" src="https://academy.hsoub.com/uploads/monthly_2021_05/oustside_data_typed_any_10.png.a1679bf69f4828bbb9ab2189383b6620.png"></a>
</p>

<p>
	يمكن إسناد القيم من النوع any إلى متغيرات من أي نوع، فلربما تكون هي القيمة المطلوبة. وهذا الأسلوب يفتقر بالتأكيد إلى عامل الأمان، لذا علينا التحقق من القيم المستقبلة سواءً استخدمنا TypeScript أو لا.
</p>

<p>
	بالإمكان إضافة آليتي تحقق بسيطتين <code>exist</code> و <code>is_value_valid</code> ضمن الدالة التي تعرّف الوجهة route، لكن من الأفضل كتابة منطق تفسير البيانات وتقييمها في ملف منفصل "utils.ts".
</p>

<p>
	لابد من تعريف الدالة <code>toNewDiaryEntry</code> التي تستقبل جسم الطلب كمعامل وتعيد كائن <code>NewDiaryEntry</code> بنوع مناسب. يستخدم تعريف الوجهة هذه الدالة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_87" style="">
<span class="kwd">import</span><span class="pln"> toNewDiaryEntry from </span><span class="str">'../utils'</span><span class="pun">;</span><span class="pln">
</span><span class="com">// ...</span><span class="pln">

router</span><span class="pun">.</span><span class="pln">post</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> newDiaryEntry </span><span class="pun">=</span><span class="pln"> toNewDiaryEntry</span><span class="pun">(</span><span class="pln">req</span><span class="pun">.</span><span class="pln">body</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">const</span><span class="pln"> addedEntry </span><span class="pun">=</span><span class="pln"> diaryService</span><span class="pun">.</span><span class="pln">addDiary</span><span class="pun">(</span><span class="pln">newDiaryEntry</span><span class="pun">);</span><span class="pln">    res</span><span class="pun">.</span><span class="pln">json</span><span class="pun">(</span><span class="pln">addedEntry</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    res</span><span class="pun">.</span><span class="pln">status</span><span class="pun">(</span><span class="lit">400</span><span class="pun">).</span><span class="pln">send</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	طالما أننا نحاول الآن كتابة شيفرة آمنة، وأن نتأكد من تلقي البيانات التي نريدها تمامًا من الطلبات، علينا أن نتحقق من ترجمة وتقييم بيانات كل حقل نتوقع أن نستقبله.
</p>

<p>
	سيبدو هيكل الدالة <code>toNewDiaryEntry</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_89" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./types'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> toNewDiaryEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">):</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> newEntry</span><span class="pun">:</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// ...</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> newEntry</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> toNewDiaryEntry</span><span class="pun">;</span></pre>

<p>
	على الدالة ترجمة كل حقل والتأكد أن نوع كل حقل من حقول القيمة المعادة هو NewDiaryEntry. ويعني هذا التحقق من كل حقل على حدى.
</p>

<p>
	ستواجهنا أيضًا في هذه المرحلة مشاكل تتعلق بالأنواع: ماهو نوع الكائن المعاد، طالما أنه جسم الطلب في الحقيقة من النوع any؟ إن فكرة هذه الدالة، هي الربط بين الحقول مجهولة النوع بحقول من النوع الصحيح والتحقق من أنها معرّفة كحقول متوقعة أولا. وربما تكون هذه الحالة هي الحالة النادرة التي سنسمح فيها باستخدام النوع any.
</p>

<p>
	سيعترض المدقق eslint على استخدام النوع any:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67117" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/eslint_warn_used_any_11.png.fd19705c5e0c57388b13377a33adc191.png" rel=""><img alt="eslint_warn_used_any_11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67117" data-unique="820ywmuzx" src="https://academy.hsoub.com/uploads/monthly_2021_05/eslint_warn_used_any_11.png.fd19705c5e0c57388b13377a33adc191.png"></a>
</p>

<p>
	وسبب ذلك، هو تفعيل القاعدة <a data-ss1621336271="1" data-ss1621337026="1" href="https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-explicit-any.md" rel="external nofollow">no-explicit-any</a> التي تمنع التصريح علنًا عن النوع any. وهي في الواقع قاعدة جيدة لكنها غير مطلوبة في هذا الجزء من الملف. يمككنا أن نتجاوز هذه القاعدة بإلغاء تفعيلها عن طريق وضع السطر التالي في ملف الشيفرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_91" style="">
<span class="com">/* eslint-disable @typescript-eslint/no-explicit-any */</span></pre>

<p>
	سنبدأ الآن بإنشاء المفسّرات لكل حقل من حقول الكائن المُعاد.
</p>

<p>
	لتقييم الحقل <code>comment</code> لابد من التحقق أنه موجود وأنه يحمل النوع string.
</p>

<p>
	ستبدو الدالة على نحو مماثل لما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_93" style="">
<span class="kwd">const</span><span class="pln"> parseComment </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">comment</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">comment </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isString</span><span class="pun">(</span><span class="pln">comment</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Incorrect or missing comment: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> comment</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">return</span><span class="pln"> comment</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تتلقى الدالة معاملُا من النوع any وتعيده من النوع string إن كان موجودًا ومن النوع الصحيح.
</p>

<p>
	ستبدو دالة تقييم النوع string كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_95" style="">
<span class="kwd">const</span><span class="pln"> isString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> text is string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> text </span><span class="pun">===</span><span class="pln"> </span><span class="str">'string'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> text instanceof </span><span class="typ">String</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	تدعى هذه الدالة أيضًا بالدالة حامية النوع <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards" rel="external nofollow">type guard</a>. وتعرَّف بأنها دالة تعيد قيمة منطقية ونوعًا إسناديُا (type predicate -يسند نوعا صريحًا لقيمة معادة-). سيكون شكل النوع الإسنادي في حالتنا هو التالي:
</p>

<pre class="ipsCode">
text is string
</pre>

<p>
	إن الشكل العام للنوع الإسنادي هو <code>parameterName is Type</code> حيث يمثل parameterName معامل الدالة ويمثل "Type" النوع الذي سيُعاد.
</p>

<p>
	فإن أعادت الدالة حامية النوع القيمة true، سيعرف مصرِّف TypeScript أن للمتغير المُختَبَر النوع ذاته الذي حدده النوع الإسنادي.
</p>

<p>
	قبل أن تُستدعى الدالة حامية للنوع سيكون النوع الفعلي للمتغير <code>comment</code> مجهولًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67110" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/comment_var_type_unknown_12.png.5fd3761d0706d54ba71c1e6e05907159.png" rel=""><img alt="comment_var_type_unknown_12.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67110" data-unique="l1tmv7k6b" src="https://academy.hsoub.com/uploads/monthly_2021_05/comment_var_type_unknown_12.png.5fd3761d0706d54ba71c1e6e05907159.png"></a>
</p>

<p>
	لكن بعد استدعائها سيعلم المصرِّف -في حال أعادت حامية النوع القيمة true، أن المتغير من النوع string.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67109" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/comment_var_type_string_13.png.56fb17827d06fb67954de90d8b09e9fd.png" rel=""><img alt="comment_var_type_string_13.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67109" data-unique="zpg4e4vt7" src="https://academy.hsoub.com/uploads/monthly_2021_05/comment_var_type_string_13.png.56fb17827d06fb67954de90d8b09e9fd.png"></a>
</p>

<p>
	لماذا نرى شرطين في حامية النوع string؟
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_98" style="">
<span class="kwd">const</span><span class="pln"> isString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> text is string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> text </span><span class="pun">===</span><span class="pln"> </span><span class="str">'string'</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> text instanceof </span><span class="typ">String</span><span class="pun">;}</span></pre>

<p>
	أليس كافيًا أن نكتب شيفرة الحامية على الشكل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_100" style="">
<span class="kwd">const</span><span class="pln"> isString </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">text</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> text is string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> text </span><span class="pun">===</span><span class="pln"> </span><span class="str">'string'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن الشكل الأبسط في أغلب الأحيان كافٍ للتطبيق العملي. لكن إن أردنا أن نكون متأكدين تمامًا لابد من وجود الشرطين. فهنالك طريقتان لإنشاء كائن من النوع string في JavaScript وكلاهما يعمل بطريقة تختلف قليلًا عن الآخر بما يتعلق باستخدام العاملين <code>typeof</code> و <code>instanceof</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_102" style="">
<span class="kwd">const</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="str">"I'm a string primitive"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> b </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">String</span><span class="pun">(</span><span class="str">"I'm a String Object"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">typeof</span><span class="pln"> a</span><span class="pun">;</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> returns </span><span class="str">'string'</span><span class="pln">
</span><span class="kwd">typeof</span><span class="pln"> b</span><span class="pun">;</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> returns </span><span class="str">'object'</span><span class="pln">
a instanceof </span><span class="typ">String</span><span class="pun">;</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> returns </span><span class="kwd">false</span><span class="pln">
b instanceof </span><span class="typ">String</span><span class="pun">;</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> returns </span><span class="kwd">true</span></pre>

<p>
	لن يفكر في الغالب أحد باستخدام الدالة البانية لإنشاء قيمة نصية، وبالتالي ستكون النسخة الأبسط للدالة الحامية مناسبة.
</p>

<p>
	لنتأمل الآن الحقل <code>date</code>. سيُترجم ويُقيَّم هذا الحقل بطريقة مشابه كثيرًا لطريقة تقييم الحقل <code>comment</code>. وطالما أن TypeScript لا تعرف نوعًا للتاريخ، سنضطر للتعامل معه كنص string. ولابد كذلك من التحقق على مستوى JavaScript أن تنسيق التاريخ مقبول.
</p>

<p>
	سنضيف الدوال التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_104" style="">
<span class="kwd">const</span><span class="pln"> isDate </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">date</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">):</span><span class="pln"> boolean </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pun">(</span><span class="typ">Date</span><span class="pun">.</span><span class="pln">parse</span><span class="pun">(</span><span class="pln">date</span><span class="pun">));</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> parseDate </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">date</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">date </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isString</span><span class="pun">(</span><span class="pln">date</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isDate</span><span class="pun">(</span><span class="pln">date</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Incorrect or missing date: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> date</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> date</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لا يوجد شيء مميز في هذه الشيفرة، لكن يجدر الإشارة أنه لا يمكن استعمال الدالة حامية النوع لأن التاريخ هنا سيعتبر من النوع string ليس إلا. ولاحظ على الرغم من أن الدالة <code>parseDate</code> تقبل المتغير <code>date</code> على أنه من النوع any، فسيتغير نوعه إلى string بعد التحقق من نوعه باستخدام <code>isString</code>. وهذا مايفسر الحاجة لقيمة نصية صحيحة التنسيق، عند تمرير المتغير إلى الدالة <code>isDate</code>.
</p>

<p>
	سننتقل الآن إلى النوعين الأخيرين Weather و Visibility.
</p>

<p>
	نريد أن تجري عمليتي الترجمة والتقييم كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_106" style="">
<span class="kwd">const</span><span class="pln"> parseWeather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">weather</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">weather </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isString</span><span class="pun">(</span><span class="pln">weather</span><span class="pun">)</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isWeather</span><span class="pun">(</span><span class="pln">weather</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Incorrect or missing weather: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> weather</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> weather</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لكن كيف يمكننا تقييم نص ما على أنه من تنسيق أو شكل محدد؟ تقتضي أحدى الطرق المتبعة، كتابة دالة حامية للنوع بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_108" style="">
<span class="kwd">const</span><span class="pln"> isWeather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">str</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">):</span><span class="pln"> str is </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="str">'sunny'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'rainy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'cloudy'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'stormy'</span><span class="pln"> </span><span class="pun">].</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">str</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	سيعمل الحل السابق بشكل جيد، لكن المشكلة أن قائمة الأحوال الجوية المحتملة قد لاتبقى متزامنة مع تعريفات النوع إن حدث أي تبديل فيها (خطأ في الكتابة مثلًا). وهذا بالطبع ليس جيدًا، لأننا نرغب بوجود مصدر وحيد لكل أنواع الطقس الممكنة.
</p>

<p>
	من الأفضل في حالتنا أن نحسَّن تعريف أنواع الطقس. فبدلًا من النوع البديل لابد من استخدام <a data-ss1621336271="1" data-ss1621337026="1" href="https://www.typescriptlang.org/docs/handbook/enums.html" rel="external nofollow">تعداد</a> TypeScript الذي يسمح لنا باستخدام القيمة الفعلية في الشيفرة في زمن التشغيل، وليس فقط في مرحلة التصريف.
</p>

<p>
	لنعد تعريف النوع Weather ليصبح كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_110" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Sunny</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'sunny'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Rainy</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'rainy'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Cloudy</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'cloudy'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Stormy</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'stormy'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Windy</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'windy'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكننا التحقق الآن أن القيمة النصية المستقبلة هي إحدى أنواع الطقس الممكنة، وستكتب الدالة الحامية للنوع كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_112" style="">
<span class="kwd">const</span><span class="pln"> isWeather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">param</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> param is </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="typ">Weather</span><span class="pun">).</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">param</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لاحظ كيف غيرنا نوع المعامل إلى any فلو كان من النوع string، لن يُترجَم التابع <code>includes</code>. وهذا منطقي وخاصة إذا أخذنا في الحسبان إعادة استخدام الدالة لاحقًا. بهذه الطريقة سنكون متأكدين تمامًا أنه أيًا كانت القيمة التي ستمرر إلى الدالة، فستخبرنا إن كانت القيمة مناسبة للطقس أو لا.
</p>

<p>
	يمكن تبسيط الدالة قليلًا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_114" style="">
<span class="kwd">const</span><span class="pln"> parseWeather </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">weather</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Weather</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">weather </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isWeather</span><span class="pun">(</span><span class="pln">weather</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Incorrect or missing weather: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> weather</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> weather</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	ستظهر مشكلة بعد هذه التغييرات. لن تلائم البيانات الأنواع التي عرّفناه بعد الآن.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67111" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/data_conform_to_type_error_14.png.1bb44381ff0cc66cbda7ee0968e510a6.png" rel=""><img alt="data_conform_to_type_error_14.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67111" data-unique="msy2od5rb" src="https://academy.hsoub.com/uploads/monthly_2021_05/data_conform_to_type_error_14.png.1bb44381ff0cc66cbda7ee0968e510a6.png"></a>
</p>

<p>
	والسبب أننا لا نستطيع ببساطة افتراض أن القيمة string على أنها تعداد enum.
</p>

<p>
	يمكننا حل المشكلة بربط عناصر البيانات الأولية (المحضرة مسبقًا) بالنوع DiaryEntry مستخدمين الدالة <code>toNewDiaryEntry</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_116" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> from </span><span class="str">"../src/types"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> toNewDiaryEntry from </span><span class="str">"../src/utils"</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"id"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"date"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"2017-01-01"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"weather"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"rainy"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"visibility"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"poor"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"comment"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Pretty scary flight, I'm glad I'm alive"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">]</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> diaryEntries</span><span class="pun">:</span><span class="pln"> </span><span class="typ">DiaryEntry</span><span class="pln"> </span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">obj </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> object </span><span class="pun">=</span><span class="pln"> toNewDiaryEntry</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">)</span><span class="pln"> as </span><span class="typ">DiaryEntry</span><span class="pln">
  object</span><span class="pun">.</span><span class="pln">id </span><span class="pun">=</span><span class="pln"> obj</span><span class="pun">.</span><span class="pln">id
  </span><span class="kwd">return</span><span class="pln"> object
</span><span class="pun">})</span><span class="pln">

</span><span class="kwd">export</span><span class="pln"> </span><span class="kwd">default</span><span class="pln"> diaryEntries</span></pre>

<p>
	وطالما أن الدالة ستعيد كائنًا من النوع NewDiaryEntry، فعلينا التأكيد على أنه من النوع DiaryEntry باستخدام العامل <a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions" rel="external nofollow">as</a>.
</p>

<p>
	يستخدم التعداد عادة عندما نكون أمام مجموعة من القيم المحددة مسبقًا ولا نتوقع تغييرها في المستقبل، خاصة القيم التي يصعب تغييرها مثل أيام الأسبوع وأسماء الأشهر وغيرها. لكن طالما أنها تقدم أسلوبًا جيدًا في تقييم القيم الواردة فمن المفيد استخدامها في حالتنا.
</p>

<p>
	وكذلك الأمر لابد من التعامل مع النوع visibility بنفس الأسلوب. سيبدو التعداد الخاص به كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_118" style="">
<span class="kwd">export</span><span class="pln"> </span><span class="kwd">enum</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="typ">Great</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'great'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Good</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'good'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Ok</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'ok'</span><span class="pun">,</span><span class="pln">
  </span><span class="typ">Poor</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'poor'</span><span class="pun">,</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وستمثل الشيفرة التالية الدالة الحامية للنوع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_120" style="">
<span class="kwd">const</span><span class="pln"> isVisibility </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">param</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> param is </span><span class="typ">Visibility</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">.</span><span class="pln">values</span><span class="pun">(</span><span class="typ">Visibility</span><span class="pun">).</span><span class="pln">includes</span><span class="pun">(</span><span class="pln">param</span><span class="pun">);</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> parseVisibility </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">visibility</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Visibility</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">visibility </span><span class="pun">||</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isVisibility</span><span class="pun">(</span><span class="pln">visibility</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Incorrect or missing visibility: '</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> visibility</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> visibility</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	وهكذا نكون قد انتهينا من إنشاء الدالة <code>toNewDiaryEntry</code> التي تتحمل مسؤولية تقييم وتفسير حقول بيانات الطلب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4891_122" style="">
<span class="kwd">const</span><span class="pln"> toNewDiaryEntry </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">object</span><span class="pun">:</span><span class="pln"> any</span><span class="pun">):</span><span class="pln"> </span><span class="typ">NewDiaryEntry</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    date</span><span class="pun">:</span><span class="pln"> parseDate</span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">date</span><span class="pun">),</span><span class="pln">
    comment</span><span class="pun">:</span><span class="pln"> parseComment</span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">comment</span><span class="pun">),</span><span class="pln">
    weather</span><span class="pun">:</span><span class="pln"> parseWeather</span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">weather</span><span class="pun">),</span><span class="pln">
    visibility</span><span class="pun">:</span><span class="pln"> parseVisibility</span><span class="pun">(</span><span class="pln">object</span><span class="pun">.</span><span class="pln">visibility</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	وبهذا ننهي النسخة الأولى من تطبيق مذكرات الرحلات الجوية!
</p>

<p>
	وفي حال أردنا إدخال مذكرة جديدة بحقول مفقودة أو غير صالحة سنحصل على رسالة الخطأ التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="67121" data-ss1621336271="1" data-ss1621337026="1" href="https://academy.hsoub.com/uploads/monthly_2021_05/new_entry_field_issue_15.png.47b441747df0a9eb7f5153f3efd13754.png" rel=""><img alt="new_entry_field_issue_15.png" class="ipsImage ipsImage_thumbnailed" data-fileid="67121" data-unique="0a5klowix" src="https://academy.hsoub.com/uploads/monthly_2021_05/new_entry_field_issue_15.png.47b441747df0a9eb7f5153f3efd13754.png"></a>
</p>

<h2>
	التمرينان 9.12 - 9.13
</h2>

<h3>
	9.12 واجهة خلفية لتطبيق إدارة المرضى: الخطوة 5
</h3>

<p>
	أنشأ وصلة تخديم للطلب POST على العنوان api/patients/ بغرض إضافة مرضى جدد. وتأكد من إمكانية إضافة مرضى عبر الواجهة الأمامية أيضًا.
</p>

<h3>
	9.13 واجهة خلفية لتطبيق إدارة المرضى: الخطوة 6
</h3>

<p>
	جد آلية أمنة لتفسير وتقييم وحماية الأنواع لطلبات HTTP-POST إلى العنوان api/patients/
</p>

<p>
	أعد كتابة الحقل <code>Gender</code> مستخدمًا التعداد (<a data-ss1621336271="1" data-ss1621337026="1" href="http://www.typescriptlang.org/docs/handbook/enums.html" rel="external nofollow">enum</a>).
</p>

<p>
	تصريف -وبتصرف- للفصل <a data-ss1621336271="1" data-ss1621337026="1" href="https://fullstackopen.com/en/part9/typing_the_express_app" rel="external nofollow">Typing the express app</a> من سلسلة <a data-ss1621336271="1" data-ss1621337026="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1216</guid><pubDate>Tue, 18 May 2021 11:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62E;&#x637;&#x648;&#x627;&#x62A; &#x627;&#x644;&#x623;&#x648;&#x644;&#x649; &#x641;&#x64A; &#x628;&#x646;&#x627;&#x621; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x628;&#x627;&#x633;&#x62A;&#x639;&#x645;&#x627;&#x644; TypeScript</title><link>https://academy.hsoub.com/programming/javascript/typescript/%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D9%88%D9%84%D9%89-%D9%81%D9%8A-%D8%A8%D9%86%D8%A7%D8%A1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84-typescript-r1215/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/6082a07d57ae4_---TypeScript.png.340aaf94ae472741334ae449266d387a.png" /></p>

<p>
	بعد المقدمة الموجزة التي تحدثنا فيها عن <a data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/programming/typescript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-typescript-r1214/" rel="">أساسيات اللغة TypeScript</a> في المقال السابق، سنكون جاهزين لبدء رحلتنا لنصبح مطورين شاملين لتطبيقات الويب باستخدام TypeScript. سنركز في هذا القسم على المشاكل التي قد تنشأ عن استخدام اللغة لتطوير تطبيقات express للواجهة الخلفية وReact للواجهة الأمامية، بدلًا من تقديم مدخل موّسع عن كل جوانب اللغة. وسنركز أيضًا على استخدام أدوات التطوير المتاحة بالإضافة إلى الميزات التي تقدمها اللغة.
</p>

<h2>
	تجهيز كل شيء لبدء العمل
</h2>

<p>
	ثَبّت ما تحتاجه لاستخدام TypeScript على المحرر الذي تختاره، ستحتاج إلى تثبيت الموسِّع <a data-ss1621334558="1" data-ss1621334878="1" href="https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero" rel="external nofollow">typescript hero</a> إن كنت ستعمل على <a data-ss1621334558="1" data-ss1621334878="1" href="https://code.visualstudio.com/" rel="external nofollow">Visual Studio Code</a>.
</p>

<p>
	لا يمكن تنفيذ شيفرة TypeScript مباشرة كما ذكرنا سابقًا، بل علينا تصريفها إلى شيفرة JavaScript قابلة للتنفيذ. عندما تصرّف شيفرة اللغة إلى JavaScript ستصبح عرضًة لإزالة الأنواع. أي ستزال مسجلات النوع والاستدلالات والأسماء المستعارة للأنواع وكل معطيات نظام تحديد النوع الأخرى، وستكون النتيجة شيفرة JavaScript صرفة جاهزة للتنفيذ.
</p>

<p>
	نقصد أحيانًا بالحاجة إلى التصريف في بيئات الإنتاج، أن نوجد "خطوة لبناء التطبيق". حيث تُصرّف كل شيفرة TypeScript خلال خطوة بناء التطبيق إلى شيفرة JavaScript ضمن مجلد منفصل، ومن ثم تُنفِّذ بيئة الإنتاج الشيفرة الموجودة ضمن هذا المجلد. يُفضَّل في بيئات الإنتاج أن نستخدم التصريف في الزمن الحقيقي، وإعادة التحميل التلقائي لنتمكن من متابعة النتائج بشكل أسرع.
</p>

<p>
	لنبدأ بكتابة أول تطبيق لنا باستخدام TypeScript. ولتبسيط الأمر، سنستخدم حزمة npm تُدعى <a data-ss1621334558="1" data-ss1621334878="1" href="https://github.com/TypeStrong/ts-node" rel="external nofollow">ts-node</a>. حيث تصرّف هذه المكتبة ملف TypeScript وتنفذه مباشرة. وبالتالي لا حاجة لخطوة تصريف مستقلة.
</p>

<p>
	يمكن تثبيت المكتبة ts-node والحزمة الرسمية للغة TypeScript لكافة المشاريع globally كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_6" style="">
<span class="pln">npm install </span><span class="pun">-</span><span class="pln">g ts</span><span class="pun">-</span><span class="pln">node typescript</span></pre>

<p>
	إن لم تستطع أو لم ترد تثبيت حزم شاملة، يمكنك إنشاء مشروع npm وتثبت فيه الاعتماديات اللازمة فقط ومن ثم تُنفِّذ شيفرتك ضمنه. كما سنستخدم المقاربة التي اتبعناها في القسم 3، حيث نهيئ مشروع npm بتنفيذ الأمر <code>npm init</code> في مجلد فارغ، ونثبّت بعدها الاعتماديات بتنفيذ الأمر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_8" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev ts</span><span class="pun">-</span><span class="pln">node typescript</span></pre>

<p>
	كما يجب أن نهيئ تعليمة <code>scripts</code> ضمن الملف package.json كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_8" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ts-node"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يمكنك استخدام ts-node ضمن المجلد بتنفيذ الأمر <code>npm run ts-node</code>. وتجدر الملاحظة أن استخدام ts-node من خلال الملف package.json يقتضي أن تبدأ كل أسطر الأوامر بالرمز "--". لذا سيكون عليك تنفيذ الأمر التالي إن أردت مثلًا تنفيذ الملف file.ts باستخدام ts-node:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_10" style="">
<span class="pln">npm run ts</span><span class="pun">-</span><span class="pln">node </span><span class="pun">--</span><span class="pln"> file</span><span class="pun">.</span><span class="pln">ts</span></pre>

<p>
	نشير أيضًا إلى وجود أرضية عمل خاصة باللغة TypeScript <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/play/index.html" rel="external nofollow">على الإنترنت</a>، حيث يمكنك تجريب شيفرتك والحصول على شيفرة JavaScript الناتجة وأخطاء التصريف المحتملة بسرعة.
</p>

<p>
	<strong>ملاحظة</strong>: يمكن أن تتضمن أرضية العمل قواعد تهيئة مختلفة (وهذا ما سنوضحه لاحقًا) عما هو موجود في بيئة التطوير الخاصة بك، لهذا قد تجد تحذيرات مختلفة. يمكن تعديل قواعد التهيئة لأرضية العمل هذه من خلال القائمة المنسدلة config.
</p>

<h3>
	ملاحظة عن أسلوب كتابة الشيفرة
</h3>

<p>
	إن لغة JavaScript بحد ذاتها مريحة الاستخدام، ويمكنك أن تنفذ ما تريده بطرق مختلفة في أغلب الأحيان. فعلى سبيل المثال يمكنك استخدام الدوال named، أو anynamous، وقد تستخدم const، أو var، أو let للتصريح عن متغير، وكذلك الاستخدامات المختلفة للفاصلة المنقوطة. سيختلف هذا القسم عن البقية بطريقة استخدام الفاصلة المنقوطة. ولا يمثل هذا الاختلاف طريقة خاصة باللغة لكنه أكثر ما يكون أسلوبًا لكتابة شيفرة أي نوع من JavaScript. واستخدام هذا التنسيق أو عدمه سيعود كليًا للمبرمج. لكن من المتوقع أن يغير أسلوبه في كتابة الشيفرة لتتماشى مع الأسلوب المتبع في هذا القسم، إذ يجب إنجاز تمارين القسم مستخدمًا الفواصل المنقوطة ومراعيًا أسلوب كتابة الشيفرة المستخدم فيه. كما ستجد اختلافًا في تنسيق الشيفرة في هذا القسم بالمقارنة مع التنسيق الذي اتبعناه في بقية أقسام المنهاج كتسمية المجلدات مثلًا.
</p>

<p>
	لنبدأ بإنشاء دالة بسيطة لتنفيذ عملية الضرب. ستبدو تمامًا كما لو أنها مكتوبة بلغة JavaScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_10" style="">
<span class="kwd">const</span><span class="pln"> multiplicator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> printText</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">printText</span><span class="pun">,</span><span class="pln">  a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

multiplicator</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Multiplied numbers 2 and 4, the result is:'</span><span class="pun">);</span></pre>

<p>
	وكما نرى، فالدالة مكتوبة بشيفرة JavaScript عادية دون استخدام ميزات TS. ستصرّف وتنفذ الشيفرة بلا مشاكل باستخدام الأمر <code>npm run ts-node -- multiplier</code>. لكن ما الذي سيحدث إن مررنا نوعًا خاطئًا من المعاملات إلى الدالة؟ لنجرب ذلك!
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_12" style="">
<span class="kwd">const</span><span class="pln"> multiplicator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> printText</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">printText</span><span class="pun">,</span><span class="pln">  a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

multiplicator</span><span class="pun">(</span><span class="str">'how about a string?'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Multiplied a string and 4, the result is:'</span><span class="pun">);</span></pre>

<p>
	عند تنفيذ الشيفرة، سيكون الخرج:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_12" style="">
<span class="pln"> </span><span class="str">"Multiplied a string and 4, the result is: NaN"</span><span class="pun">.</span></pre>

<p>
	أليس من الجيد أن تمنعنا اللغة من ارتكاب هذا الخطأ؟ سترينا هذه المشكلة أولى مزايا TS. لنعرف أنواعًا للمعاملات ونرى ما الذي سيتغير.
</p>

<p>
	تدعم اللغة TS أنواعًا مختلفة، مثل: number، وstring، وArray. يمكنك إيجاد قائمة بالأنواع في <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/basic-types.html" rel="external nofollow">توثيق TS</a> على الانترنت. كما يمكن إنشاء أنواع مخصصة أكثر تعقيدًا.
</p>

<p>
	إنّ أول معاملين لدالة الضرب من النوع <a data-ss1621334558="1" data-ss1621334878="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#number" rel="external nofollow">number</a> والثالث من النوع <a data-ss1621334558="1" data-ss1621334878="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#string" rel="external nofollow">string</a>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_14" style="">
<span class="kwd">const</span><span class="pln"> multiplicator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> printText</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">printText</span><span class="pun">,</span><span class="pln">  a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

multiplicator</span><span class="pun">(</span><span class="str">'how about a string?'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="str">'Multiplied a string and 4, the result is:'</span><span class="pun">);</span></pre>

<p>
	لم تعد الشيفرة السابقة شيفرة JavaScript صالحة للتنفيذ. فلو حاولنا تنفيذها، لن تُصرَّف:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64465" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/code_no_compile_01.png.b1c04d2b204bbed6ccbbdec463214f0b.png" rel=""><img alt="code_no_compile_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64465" data-unique="3gnvo3gzi" src="https://academy.hsoub.com/uploads/monthly_2021_04/code_no_compile_01.png.b1c04d2b204bbed6ccbbdec463214f0b.png"></a>
</p>

<p>
	إنّ إحدى أفضل ميزات محرر TS، أنك لن تحتاج إلى تنفيذ الشيفرة حتى ترى المشكلة. فالإضافة VSCode فعالة جدًا، حيث ستبلغك مباشرة إن حاولت استخدام النوع الخاطئ.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64478" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/vscode_warning_02.png.45513d44841c8cc06d518251b13fb825.png" rel=""><img alt="vscode_warning_02.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64478" data-unique="i84hdm0pr" src="https://academy.hsoub.com/uploads/monthly_2021_04/vscode_warning_02.png.45513d44841c8cc06d518251b13fb825.png"></a>
</p>

<h2>
	إنشاء أول نوع خاص بك
</h2>

<p>
	لنطور دالة الضرب إلى آلة حاسبة تدعم أيضًا الجمع والقسمة. ينبغي أن تقبل الآلة الحاسبة ثلاث معاملات: عددين وعملية قد تكون الضرب multiply، أو الجمع add، أو القسمة divide.
</p>

<p>
	تحتاج الشيفرة في JavaScript إلى تقييم إضافي للمعامل الثالث لتتأكد من كونه قيمة نصية. بينما تقدم TS طريقة لتعريف أنواع محددة من الدخل، بحيث تصف تمامًا الأنواع المقبولة. وعلاوة على ذلك، ستظهر لك TS معلومات عن القيم الصالحة للاستخدام ضمن المحرر.
</p>

<p>
	يمكن إنشاء نوع باستخدام التعليمة الداخلية <code>type</code> في TS. سنصف فيما سيأتي النوع Operation الذي عرًفناه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_16" style="">
<span class="pln">type </span><span class="typ">Operation</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'add'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">;</span></pre>

<p>
	يقبل النوع Op ثلاثة أشكال من الدخل وهي تمامًا القيم النصية الثلاثة التي نريد. يمكننا باستخدام العامل OR ('|') تعريف متغير يقبل قيمًا متعددة وذلك بإنشاء نوع موحَّد <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types" rel="external nofollow">union type</a>.لقد استخدمنا في الحالة السابقة القيمة النصية بحرفيتها (وهذا ما يدعى التعريف المختصر للنوع النصي <a data-ss1621334558="1" data-ss1621334878="1" href="http://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types" rel="external nofollow">string literal types</a>)، لكن باستخدام الأنواع الموحَّدة، ستجعل المصرِّف قادرًا على قبول قيمة نصية أو عددية: <code>string | number</code>.
</p>

<p>
	تُعرّف التعليمة <code>type</code> اسمًا جديدًا للنوع أو ما يسمى <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases" rel="external nofollow">اسمًا مستعارًا للنوع</a>. وطالما أن النوع المُعرَّف هو اتحاد بين ثلاث قيم مقبولة، فمن المفيد إعطاء النوع اسمًا مستعارًا يصفه بشكل جيد.
</p>

<p>
	لنلق نظرة على الآلة الحاسبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_18" style="">
<span class="pln">type </span><span class="typ">Operation</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'add'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> op </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Operation</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'add'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'can\'t divide by 0!'</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستلاحظ الآن أنك لو مررت الفأرة فوق النوع <code>Operation</code> في المحرر، ستظهر لك مباشرة اقتراحات عن طريقة استخدامه:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64473" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/type_use_suggestione_03.png.ba430d5afccd70fae5606fd4f3831262.png" rel=""><img alt="type_use_suggestione_03.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64473" data-unique="gp1jk833v" src="https://academy.hsoub.com/uploads/monthly_2021_04/type_use_suggestione_03.png.ba430d5afccd70fae5606fd4f3831262.png"></a>
</p>

<p>
	ولو أردنا استخدام قيمة غير موجودة ضمن النوع <code>Operation</code>، ستظهر لك مباشرة إشارة التحذير الحمراء ومعلومات إضافية ضمن المحرر:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64472" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/type_mismatch_warn_04.png.40de01b1d47e6b09a104e4ba8974ab11.png" rel=""><img alt="type_mismatch_warn_04.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64472" data-unique="qk7ijhyva" src="https://academy.hsoub.com/uploads/monthly_2021_04/type_mismatch_warn_04.png.40de01b1d47e6b09a104e4ba8974ab11.png"></a>
</p>

<p>
	لقد أبلينا جيدًا حتى اللحظة، لكننا لم نطبع بعد النتيجة التي تعيدها دالة الآلة الحاسبة. غالبًا ما نريد معرفة النتيجة التي تعيدها الدالة، ومن الأفضل أن نضمن أن الدالة ستعيد القيمة التي يفترض أن تعيدها. لنضف إذًا القيمة المعادة <code>number</code> إلى الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_20" style="">
<span class="pln">type </span><span class="typ">Operation</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'add'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> op</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Operation</span><span class="pun">):</span><span class="pln"> number </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'add'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">op </span><span class="pun">===</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> </span><span class="str">'this cannot be done'</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيعترض المصرِّف مباشرة على فعلتنا، ذلك أن الدالة ستعيد في إحدى الحالات (القسمة على صفر) قيمة نصية. هناك عدة طرق لحل المشكلة. إذ يمكن إعادة تعريف النوع المعاد ليتضمن القيم النصية string على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_22" style="">
<span class="kwd">const</span><span class="pln"> calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> op</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Operation</span><span class="pun">):</span><span class="pln"> number </span><span class="pun">|</span><span class="pln"> string </span><span class="pun">=&gt;</span><span class="pln">  </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	أو قد ننشئ نوعًا جديدًا للقيم المعادة يتضمن النوعين اللذين تعيدهما الدالة تمامًا مثل النوع Operation.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_24" style="">
<span class="pln">type </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> string </span><span class="pun">|</span><span class="pln"> number

</span><span class="kwd">const</span><span class="pln"> calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> op</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Operation</span><span class="pun">):</span><span class="pln"> </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln">  </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لكن السؤال الذي يطرح نفسه هو: هل من الطبيعي لدالة أن تعيد قيمة نصة؟
</p>

<p>
	عندما تصل أثناء كتابة الشيفرة إلى حالة تضطر فيها إلى التقسيم على صفر، فإن خطأً جسيمًا قد وقع في مرحلة ما، وينبغي أن يلقي التطبيق خطأً ثم يعالج عند استدعاء الدالة. عندما تحاول أن تعيد قيمًا لم تكن تتوقعها أصلًا، ستمنعك التحذيرات التي تراها في محرر TSمن اتخاذ قرارات متسرعة، وتضمن لك عمل شيفرتك كما أردتها.
</p>

<p>
	وعليك أن تدرك أمرًا آخر، فحتى لو عرّفنا أنواعًا لمعاملاتنا، فإن شيفرة JavaScript المتولدة عند التصريف لن تكون قادرة على التحقق من هذه الأنواع أثناء التنفيذ. وإن كانت قيمة المعامل الذي يحدد العملية قادمةً من مكتبة خارجية على سبيل المثال، فلن تضمن أنها واحدة من القيم المسموحة. لذلك من الأفضل أن تنشئ معالجات للأخطاء، وأن تكون منتبهًا لحدوث ما لا تتوقعه. وفي الحالة التي تصادفك فيها عدة قيم مقبولة بينما ينبغي رفض بقية القيم وإلقاء خطأ، ستجد أن كتلة <a data-ss1621334558="1" data-ss1621334878="1" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch" rel="external nofollow">switch…case</a> أكثر ملائمة من كتلة "if….else".
</p>

<p>
	ستبدو شيفرة الآلة الحاسبة التي طورناها على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_26" style="">
<span class="pln">type </span><span class="typ">Operation</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'add'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">;</span><span class="pln">

type </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> calculator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> op </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Operation</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Result</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">switch</span><span class="pun">(</span><span class="pln">op</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'multiply'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">if</span><span class="pun">(</span><span class="pln"> b </span><span class="pun">===</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Can\'t divide by 0!'</span><span class="pun">);</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">/</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">case</span><span class="pln"> </span><span class="str">'add'</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">default</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Operation is not multiply, add or divide!'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">calculator</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> </span><span class="str">'divide'</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Something went wrong, error message: '</span><span class="pun">,</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا بأس بما فعلنا حتى الآن، لكن من الأفضل لو استخدمنا سطر الأوامر لإدخال القيم بدلًا من تغييرها ضمن الشيفرة في كل مرة. سنجرب ذلك كما لو كنا ننفذ تطبيق Node نظامي، باستخدام <code>process.argv</code>. لكن مشكلة ستقع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64469" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/cpmmand_line_node_problem_05.png.bc3483ba4c616c61dbf760c044993585.png" rel=""><img alt="cpmmand_line_node_problem_05.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64469" data-unique="32p7ui71f" src="https://academy.hsoub.com/uploads/monthly_2021_04/cpmmand_line_node_problem_05.png.bc3483ba4c616c61dbf760c044993585.png"></a>
</p>

<h2>
	الحصول على الأنواع في حزم npm من خلال Type@
</h2>

<p>
	لنعد إلى الفكرة الأساسية للغة TS. تتوقع اللغة أن تكون كل الشيفرة المستخدمة قادرة على تمييز الأنواع، كما تتوقع ذلك من شيفرة مشروعك الخاص الذي هيِّئ بشكل مناسب. ولا تتضمن المكتبة TS بذاتها سوى الأنواع الموجودة في الحزمة TS. من الممكن كتابة أنواع خاصة بك لمكتبة، لكن ذلك غير ضروري إطلاقًا! فمجتمع TS قد فعل ذلك بالنيابة عنّا.
</p>

<p>
	وكما هو حال npm، يرحب عالم TS بالشيفرة مفتوحة المصدر. ومجتمع TS مجتمع نشط ويتفاعل دومًا مع آخر التحديثات والتغييرات في حزم npm المستخدمة أكثر.
</p>

<p>
	ستجد غالبًا كل ماتحتاجه من أنواع حزم npm، فلا حاجة لإنشاء هذه الأنواع بنفسك لكل اعتمادية قد تستخدمها.
</p>

<p>
	عادة ما نحصل على الأنواع المعرّفة في الحزم الموجودة من خلال منظمة Types@ وباستخدام npm. إذ يمكنك إضافة الأنواع الموجودة في حزمة إلى مشروعك بتثبيت حزمة npm لها نفس اسم حزمتك لكنه مسبوق بالبادئة Types@. فعلى سبيل المثال ستُثبَّت الأنواع التي توفرها المكتبة express بتنفيذ الأمر <code>npm install --save-dev @types/express</code>. تجري صيانة وتطوير Types@ من قبل <a data-ss1621334558="1" data-ss1621334878="1" href="http://definitelytyped.org/" rel="external nofollow">Definitely typed</a>، وهو مشروع مجتمعي يهدف إلى صيانة أنواع كل ما هو موجود في مكان واحد.
</p>

<p>
	قد تحتوي حزمة npm في بعض الأحيان الأنواع الخاصة بها ضمن الشيفرة، فلا حاجة في هذه الحالة إلى تثبيت تلك الأنواع بالطريقة التي ذكرنا سابقًا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		ملاحظة: لاحاجة لتمييز الأنواع في نسخة الإنتاج طالما أن تمييز الأنواع سيجري قبل التصريف. لذلك ينبغي أن يبقى تعريف الأنواع في قسم اعتماديات التطوير داخل ملف package.json.
	</p>
</blockquote>

<p>
	طالما أن المتغير العام <code>process</code> قد عُرِّف من قبل Node، سنحصل على الأنواع التي يؤمنها بتثبيت الحزمة types/node@:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_14" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev </span><span class="lit">@types</span><span class="pun">/</span><span class="pln">node</span></pre>

<p>
	لن يعترض المصرِّف على المتغير <code>process</code> بعد تثبيت الأنواع. ولاحظ أنه لا حاجة لطلب الأنواع ضمن الشيفرة، إذ يكفي تثبيت الحزمة التي تُعرِّفها.
</p>

<h2>
	تحسينات على المشروع
</h2>

<p>
	سنضيف تاليًا سيكربت npm لتشغيل كلا من برنامج دالة الضرب، وبرنامج الآلة الحاسبة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_28" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"name"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"part1"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"version"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"1.0.0"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"description"</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"main"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"index.js"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ts-node"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"multiply"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node multiplier.ts"</span><span class="pun">,</span><span class="pln">    </span><span class="str">"calculate"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node calculator.ts"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"author"</span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"license"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ISC"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"devDependencies"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ts-node"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^8.6.2"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"typescript"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^3.8.2"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنجعل دالة الضرب تعمل من خلال سطر الأوامر عند إجراء التعديلات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_32" style="">
<span class="kwd">const</span><span class="pln"> multiplicator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> printText</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">printText</span><span class="pun">,</span><span class="pln">  a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> a</span><span class="pun">:</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">2</span><span class="pun">])</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">3</span><span class="pun">])</span><span class="pln">
multiplicator</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Multiplied</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">a</span><span class="pun">}</span><span class="pln"> and $</span><span class="pun">{</span><span class="pln">b</span><span class="pun">},</span><span class="pln"> the result is</span><span class="pun">:`);</span></pre>

<p>
	وسننفذ البرنامج كالتالي:
</p>

<pre class="ipsCode">
npm run multiply 5 2
</pre>

<p>
	لو نفذنا البرنامج بمعاملات ليست من النوع الصحيح، كما تُظهر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_21" style="">
<span class="pln">npm run multiply </span><span class="lit">5</span><span class="pln"> lol</span></pre>

<p>
	سيعمل البرنامج أيضًا معطيًا الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_19" style="">
<span class="typ">Multiplied</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> and </span><span class="kwd">NaN</span><span class="pun">,</span><span class="pln"> the result is</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">NaN</span></pre>

<p>
	والسبب في ذلك أن تنفيذ الأمر <code>('Number('lol</code> سيعيد القيمة NaN وهذه القيمة من النوع number. لهذا لا يمكن أن تنقذنا TS من مأزق كهذا.
</p>

<p>
	لا بدّ في هذه الحالات من تقييم البيانات التي نحصل عليها من سطر الأوامر لكي نمنع سلوكًا كهذا.
</p>

<p>
	ستبدو النسخة المحسّنة من "دالة الضرب" كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_34" style="">
<span class="pln">interface </span><span class="typ">MultiplyValues</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value1</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  value2</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> parseArguments </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="pln">string</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">MultiplyValues</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Not enough arguments'</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Too many arguments'</span><span class="pun">);</span><span class="pln">

  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">isNaN</span><span class="pun">(</span><span class="typ">Number</span><span class="pun">(</span><span class="pln">args</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">!</span><span class="pln">isNaN</span><span class="pun">(</span><span class="typ">Number</span><span class="pun">(</span><span class="pln">args</span><span class="pun">[</span><span class="lit">3</span><span class="pun">])))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      value1</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">args</span><span class="pun">[</span><span class="lit">2</span><span class="pun">]),</span><span class="pln">
      value2</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Number</span><span class="pun">(</span><span class="pln">args</span><span class="pun">[</span><span class="lit">3</span><span class="pun">])</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Error</span><span class="pun">(</span><span class="str">'Provided values were not numbers!'</span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> multiplicator </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> printText</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">printText</span><span class="pun">,</span><span class="pln">  a </span><span class="pun">*</span><span class="pln"> b</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value1</span><span class="pun">,</span><span class="pln"> value2 </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> parseArguments</span><span class="pun">(</span><span class="pln">process</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">);</span><span class="pln">
  multiplicator</span><span class="pun">(</span><span class="pln">value1</span><span class="pun">,</span><span class="pln"> value2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Multiplied</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">value1</span><span class="pun">}</span><span class="pln"> and $</span><span class="pun">{</span><span class="pln">value2</span><span class="pun">},</span><span class="pln"> the result is</span><span class="pun">:`);</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="str">'Error, something bad happened, message: '</span><span class="pun">,</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">message</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما ننفذ البرنامج الآن:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_24" style="">
<span class="pln">npm run multiply </span><span class="lit">1</span><span class="pln"> lol</span></pre>

<p>
	سنحصل على رسالة خطأ مناسبة للوضع:
</p>

<pre class="ipsCode">
Error, something bad happened, message:  Provided values were not numbers!
</pre>

<p>
	يحتوي تعرف الدالة <code>parseArguments</code> بعض الأشياء الملفتة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_36" style="">
<span class="kwd">const</span><span class="pln"> parseArguments </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">args</span><span class="pun">:</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">&lt;</span><span class="pln">string</span><span class="pun">&gt;):</span><span class="pln"> </span><span class="typ">MultiplyValues</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنجد أولًا أنّ المعامل <code>arg</code> هو <a data-ss1621334558="1" data-ss1621334878="1" href="http://www.typescriptlang.org/docs/handbook/basic-types.html#array" rel="external nofollow">مصفوفة</a> من النوع "string"، وأنّ القيم المعادة من النوع "MultiplayValues" الذي عُرِّف بالشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_38" style="">
<span class="pln">interface </span><span class="typ">MultiplyValues</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  value1</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
  value2</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لقد استخدمنا في تعريف هذا النوع التعليمة <a data-ss1621334558="1" data-ss1621334878="1" href="http://www.typescriptlang.org/docs/handbook/interfaces.html" rel="external nofollow">Interface</a> للغة TS، وهي إحدى الطرق المتبعة لتحديد شكل الكائن. إذ ينبغي كما هو واضح في حالتنا، أن تكون القيمة المعادة كائنًا له خاصيتين <code>value1</code> و<code>value2</code> من النوع "number".
</p>

<h2>
	التمارين 9.1 - 9.3
</h2>

<h3>
	التثبيت
</h3>

<p>
	سننجز التمارين من 9.1 إلى 9.7 ضمن مشروع Node واحد. أنشئ المشروع في مجلد فارغ مستخدمًا الأمر <code>npm init</code> وثبِّت حزمتي ts-node وtypescript. أنشئ أيضًا ملفًا باسم tsconfig.json ضمن المجلد بحيث يحتوي الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_40" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"noImplicitAny"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستخدم هذا الملف لتحديد الطريقة التي سيفسر بها مصرِّف TS الشيفرة المكتوبة، وما هو مقدار التشدد الذي سيفرضه المصرِّف، وما هي الملفات التي ينبغي مراقبتها أو تجاهلها، و<a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html" rel="external nofollow">الكثير الكثير من الأشياء</a>. سنستخدم حاليًا خيار المصرِّف <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/tsconfig#noImplicitAny" rel="external nofollow">noImplicitAny</a> الذي يشترط أن تحمل جميع المتغيرات أنواعًا محددة.
</p>

<h3>
	9.1 مؤشر كتلة الجسم
</h3>

<p>
	ضع شيفرة هذا التمرين في الملف bmiCalculator.ts.
</p>

<p>
	اكتب دالة باسم <code>calculateBmi</code> تحسب مؤشر كتلة الجسم <a data-ss1621334558="1" data-ss1621334878="1" href="https://en.wikipedia.org/wiki/Body_mass_index" rel="external nofollow">BMI</a> بناء على طول محدد (سنتيمتر) ووزن محدد (كيلو غرام)، ثم أعد رسالة مناسبة تحمل النتيجة.
</p>

<p>
	استدعي الدالة من شيفرتك ومرر إليها معاملات جاهزة ثم اطبع النتيجة.
</p>

<p>
	ينبغي أن تطبع الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_42" style="">
<span class="pln">console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">calculateBmi</span><span class="pun">(</span><span class="lit">180</span><span class="pun">,</span><span class="pln"> </span><span class="lit">74</span><span class="pun">))</span></pre>

<p>
	النتيجة التالية:
</p>

<pre class="ipsCode">
Normal (healthy weight)
</pre>

<p>
	أنشئ سكربت npm لكي تنفذ البرنامج باستخدام الأمر <code>npm run calculateBmi</code>
</p>

<h3>
	9.2 آلة حاسبة لساعات التمرين
</h3>

<p>
	ضع شيفرة هذا التمرين في الملف exerciseCalculatore.ts.
</p>

<p>
	اكتب دالة باسم calculateExercise تحسب متوسط ساعات التمرين اليومية وتقارنها بعدد الساعات التي ينبغي الوصول إليها يوميًا، ثم تعيد كائنًا يتضمن القيم التالية:
</p>

<ul>
<li>
		عدد الأيام
	</li>
	<li>
		عدد أيام التمرين
	</li>
	<li>
		القيمة المستهدفة أساسًا
	</li>
	<li>
		متوسط الوقت المحسوب
	</li>
	<li>
		قيمة منطقية تحدد إن تم تحقيق الهدف أم لا.
	</li>
	<li>
		تقييمًا بين 1-3 يصف حسن التمرين خلال ساعات التمرين. قرر أسلوب التقييم كما تشاء.
	</li>
	<li>
		قيمة نصية تصف التقييم
	</li>
</ul>
<p>
	تمرر ساعات التمرين اليومية إلى الدالة مثلل <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/basic-types.html#array" rel="external nofollow">مصفوفة</a> تحتوي على عدد ساعات التمرين كل يوم خلال فترة التمرين. فلو فرضنا أن ساعات التمرين خلال أسبوع موزعة كالتالي: يوم الاثنين 3، يوم الثلاثاء 0، يوم الأربعاء 2، يوم الخميس 4.5 وهكذا، ستكون المصفوفة مشابهة للمصفوفة التالية:
</p>

<pre class="ipsCode">
[3, 0, 2, 4.5, 0, 3, 1]
</pre>

<p>
	عليك أن تنشئ واجهة interface من أجل توصيف الكائن الذي سيحمل النتيجة.
</p>

<p>
	لو استدعيت الدالة وقد مررت لها المصفوفة [3, 0, 2, 4.5, 0, 3, 1] والقيمة 2 للمعامل الآخر ستكون النتيجة على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_45" style="">
<span class="pun">{</span><span class="pln"> periodLength</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
  trainingDays</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln">
  success</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  rating</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  ratingDescription</span><span class="pun">:</span><span class="pln"> </span><span class="str">'not too bad but could be better'</span><span class="pun">,</span><span class="pln">
  target</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  average</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.9285714285714286</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	أنشئ سكربت npm لينفذ الأمر <code>npm run calculateExercise</code> الذي يستدعي الدالة بمعاملات قيمها موجودة مسبقًا في الشيفرة.
</p>

<h3>
	9.3 سطر الأوامر
</h3>

<p>
	عدّل التمرينين السابقين بحيث يمكنك تمرير قيم معاملات الدالتين <code>calculateBmi</code> و<code>calculateExercise</code> من خلال سطر الأوامر.
</p>

<p>
	يمكن أن تنفذ برنامجك على سبيل المثال على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_30" style="">
<span class="pln">$ npm run calculateBmi </span><span class="lit">180</span><span class="pln"> </span><span class="lit">91</span><span class="pln">

</span><span class="typ">Overweight</span></pre>

<p>
	أو على النحو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_32" style="">
<span class="pln">$ npm run calculateExercises </span><span class="lit">2</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">4.5</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">4</span><span class="pln">

</span><span class="pun">{</span><span class="pln"> periodLength</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln">
  trainingDays</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln">
  success</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
  rating</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  ratingDescription</span><span class="pun">:</span><span class="pln"> </span><span class="str">'not too bad but could be better'</span><span class="pun">,</span><span class="pln">
  target</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
  average</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.7222222222222223</span><span class="pln"> </span><span class="pun">}</span></pre>

<p>
	وانتبه إلى أنّ المعامل الأول للدالة السابقة هو القيمة المستهدفة.
</p>

<p>
	تعامل مع الاستثناءات والأخطاء بطريقة مناسبة. وانتبه إلى أنّ الدالة <code>exerciseCalculator</code> ستقبل قيمًا لمعاملاتها بأطوال مختلفة. قرر بنفسك كيف ستجمّع كل البيانات المطلوبة.
</p>

<h2>
	المزيد حول قواعد تهيئة TS
</h2>

<p>
	لقد استخدمنا في التمارين السابقة قاعدة تهيئة واحدة هي noImplicitAny. وهي بالفعل نقطة انطلاق جيدة، لكن يجب أن نطلع بشيء من التفصيل على الملف "config".
</p>

<p>
	يحتوي الملف <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/tsconfig-json.html" rel="external nofollow">tsconfig.json</a> كل التفاصيل الجوهرية التي تحدد الطريقة التي ستنفذ بها TS مشروعك. فيمكنك أن تحدد مقدار التشدد في تفحص الشيفرة، وأن تحدد الملفات التي ستدرجها في المشروع والتي ستستثنيها (يستثنى الملف "node_modules" افتراضيًا)، وأين ستخزّن الملفات المصرِّفة (سنتحدث أكثر عن هذا الموضوع لاحقًا).
</p>

<p>
	لنضع القواعد التالية في الملف tsconfig.json:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_48" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ES2020"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strict"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedLocals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedParameters"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noImplicitReturns"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noFallthroughCasesInSwitch"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"esModuleInterop"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لا تقلق بخصوص القواعد في الجزء compilerOptions من الملف، فسنمر عليها بشيئ من التفصيل في القسم 2.
</p>

<p>
	يمكنك أن تجد شروحات عن كل قاعدة تهيئة من خلال توثيق TS، أو من خلال صفحة الويب <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.staging-typescript.org/tsconfig" rel="external nofollow">tsconfig page</a>، أو من خلال <a data-ss1621334558="1" data-ss1621334878="1" href="http://json.schemastore.org/tsconfig" rel="external nofollow">تعريف تخطيط</a> الملف tsconfig والذي صيغ لسوء الحظ بطريقة أقل وضوحًا من الخيارين السابقين.
</p>

<h2>
	إضافة المكتبة express إلى الخلطة
</h2>

<p>
	وصلنا إلى مرحلة لا بأس بها. فمشروعنا قد ثّبت، ويحتوي على نسخة قابلة للتنفيذ من الآلة الحاسبة. لكن طالما أنا نهتم بالتطوير الشامل لتطبيقات الويب، فقد حان الوقت لنعمل مع بعض طلبات HTTP.
</p>

<p>
	لنبدأ بتثبيت المكتبة express:
</p>

<pre class="ipsCode">
npm install express
</pre>

<p>
	ثم سنضيف سكربت start إلى الملف package.json
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_50" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ts-node"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"multiply"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node multiplier.ts"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"calculate"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node calculator.ts"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node index.ts"</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ..</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سنتمكن الآن من إنشاء الملف index.ts، ثم سنكتب ضمنه طلب HTTP-GET للتحقق من الاتصال بالخادم:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_52" style="">
<span class="kwd">const</span><span class="pln"> express </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'express'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> app </span><span class="pun">=</span><span class="pln"> express</span><span class="pun">();</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/ping'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="str">'pong'</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> PORT </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3003</span><span class="pun">;</span><span class="pln">

app</span><span class="pun">.</span><span class="pln">listen</span><span class="pun">(</span><span class="pln">PORT</span><span class="pun">,</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(`</span><span class="typ">Server</span><span class="pln"> running on port $</span><span class="pun">{</span><span class="pln">PORT</span><span class="pun">}`);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	يبدو أن كل شيء يعمل على ما يرام، لكن كما هو متوقع، لا بدّ من تحديد نوع كل من المعاملين <code>req</code> و<code>res</code> للدالة <code>app.get</code> (لأننا وضعنا قاعدة تهيئة تفرض أن يكون لكل متغير نوع). لو نظرت جيدًا، ستجد أن VSCode سيعترض على إدراج express. ستجد خطًا منقطا أصفر اللون تحت التعليمة <code>require</code>. وعندما نمرر الفأرة فوق الخطأ ستظهر الرسالة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64477" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/vscode_express_import_propblem_06.png.fab3e754f9a61696a9e4ebbbb09b7827.png" rel=""><img alt="vscode_express_import_propblem_06.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64477" data-unique="5i23y46e5" src="https://academy.hsoub.com/uploads/monthly_2021_04/vscode_express_import_propblem_06.png.fab3e754f9a61696a9e4ebbbb09b7827.png"></a>
</p>

<p>
	إنّ سبب الاعتراض هو أن <code>require</code> يمكن أن تُحوَّل إلى <code>import</code>. لننفذ النصيحة ونستخدم <code>import</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_35" style="">
<span class="kwd">import</span><span class="pln"> express from </span><span class="str">'express'</span><span class="pun">;</span></pre>

<p>
	<strong>ملاحظة</strong>: تقدم لك VSCode ميزة إصلاح المشاكل تلقائيًا بالنقر على زر "…Quick fix". انتبه إلى تلك الاصلاحات التلقائية، وحاول أن تتابع النصائح التي يقدمها محرر الشيفرة، لأن ذلك سيحسّن من شيفرتك ويجعلها أسهل قراءة. كما يمكن أن يكون الإصلاح التلقائي للأخطاء عاملًا رئيسيًا في توفير الوقت.
</p>

<p>
	سنواجه الآن مشكلة جديدة. سيعترض المصرِّف على عبارة <code>import</code>. وكالعادة يمثل المحرر المكان الأفضل لإيجاد حلول للمشاكل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64466" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_error_using_import_07.png.2606cca8b49d6c6649b416ae81defb20.png" rel=""><img alt="compiler_error_using_import_07.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64466" data-unique="l6ij6ixi7" src="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_error_using_import_07.png.2606cca8b49d6c6649b416ae81defb20.png"></a>
</p>

<p>
	لم نثبّت أنواع express كما يشير المحرر، لنثبتها إذًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_37" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev </span><span class="lit">@types</span><span class="pun">/</span><span class="pln">express</span></pre>

<p>
	وهكذا سيعمل البرنامج بلا أخطاء.
</p>

<p>
	فلو مررنا الفأرة على عبارة <code>require</code> سنرى أن المصرِّف قد فسّر كل ما يتعلق بالمكتبة express على أنه من النوع "any".
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64468" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_require_type_issue_08.png.68c10ad2cba88c0213dcd582d27ca2d5.png" rel=""><img alt="compiler_require_type_issue_08.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64468" data-unique="f3f3v4l5m" src="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_require_type_issue_08.png.68c10ad2cba88c0213dcd582d27ca2d5.png"></a>
</p>

<p>
	لكن عند استخدام <code>imports</code> فسيعرف المصرِّف الأنواع الفعلية للمتغيرات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64467" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_imports_type_rec_09.png.924756b5418e6864b13327edcfcfbc2d.png" rel=""><img alt="compiler_imports_type_rec_09.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64467" data-unique="bu1uxx54l" src="https://academy.hsoub.com/uploads/monthly_2021_04/compiler_imports_type_rec_09.png.924756b5418e6864b13327edcfcfbc2d.png"></a>
</p>

<p>
	يعتمد استخدام عبارة الإدراج على أسلوب التصدير الذي تعتمده الحزمة التي ندرجها. وكقاعدة أساسية: حاول أن تدرج وحدات الشيفرة باستخدام التعليمة <code>import</code> أولًا. سنستخدم دائمًا هذا الأسلوب عند كتابة شيفرة الواجهة الأمامية. فإن لم تنجح التعليمة <code>import</code>، جرّب طريقة مختلطة بتنفيذ الأمر <code>('...')import...= require</code>. كما نوصيك بشدة أن تطلع أكثر على <a data-ss1621334558="1" data-ss1621334878="1" href="https://www.typescriptlang.org/docs/handbook/modules.html" rel="external nofollow">وحدات TS</a>.
</p>

<p>
	لا تزال هنالك مشكلة عالقة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64464" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/ban_unused_param_10.png.5e8e5c948844aca8c2b422e1d8a2f323.png" rel=""><img alt="ban_unused_param_10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64464" data-unique="hcuxech3q" src="https://academy.hsoub.com/uploads/monthly_2021_04/ban_unused_param_10.png.5e8e5c948844aca8c2b422e1d8a2f323.png"></a>
</p>

<p>
	يحدث هذا لأننا منعنا وجود معاملات غير مستخدمة عند كتابة قواعد التهيئة في الملف tsconfig.json.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_54" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ES2020"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strict"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedLocals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedParameters"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">    </span><span class="str">"noImplicitReturns"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noFallthroughCasesInSwitch"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"esModuleInterop"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ستسبب لك التهيئة مشاكلًا إن استخدمت دوال معرّفة مسبقُا لمكتبة وتتطلب تصريحًا عن متغير حتى لو لم يستخدم مطلقًا كالحالة التي تواجهنا. ولحسن الحظ فقد حُلًت هذه المشكلة على مستوى قواعد التهيئة. وبمجرد تمرير مؤشر الفأرة فوق الشيفرة التي سببت المشكلة سيعطينا فكرة الحل. وسننجز الحل هذه المرة بالنقر على زر الإصلاح السريع.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64475" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/unused_variable_issue_solution_11.png.635294bfb17ad638c3c5411119c4834a.png" rel=""><img alt="unused_variable_issue_solution_11.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64475" data-unique="6yz3oatdj" src="https://academy.hsoub.com/uploads/monthly_2021_04/unused_variable_issue_solution_11.png.635294bfb17ad638c3c5411119c4834a.png"></a>
</p>

<p>
	إن كان من المستحيل التخلص من المتغيرات غير المستخدمة، يمكنك أن تضيف إليها البادئة (_) لإبلاغ المصرِّف بأنك قد فكرت بحل ولم تصل إلى نتيجة!
</p>

<p>
	لنعدّل اسم المتغير <code>req</code> ليصبح <code>req_</code>.
</p>

<p>
	وأخيرًا سنكون مستعدين لتشغيل البرنامج. ويبدو أن كل شيء على مايرام.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64471" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/program_on_run_12.png.eb50689d01177c26dea8548c546a168c.png" rel=""><img alt="program_on_run_12.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64471" data-unique="sfjvp5vb7" src="https://academy.hsoub.com/uploads/monthly_2021_04/program_on_run_12.png.eb50689d01177c26dea8548c546a168c.png"></a>
</p>

<p>
	ولتبسيط عملية التطوير، ينبغي علينا تمكين ميزة إعادة التحميل التلقائي، وذلك لتحسين انسيابية العمل. لقد استخدمنا سابقًا المكتبة nodemon التي توفر هذه الميزة، لكن البديل عنها في ts-node هي المكتبة ts-node-dev. وقد جرى تصميم هذه الأخيرة لتُستخدم فقط في بيئة التطوير، حيث تتولى أمور إعادة التصريف عند كل تغيير، وبالتالي لا حاجة لإعادة تشغيل التطبيق.
</p>

<p>
	لنثبّت المكتبة ts-node-dev كاعتمادية تطوير:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5559_39" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev ts</span><span class="pun">-</span><span class="pln">node</span><span class="pun">-</span><span class="pln">dev</span></pre>

<p>
	ثم علينا إضافة سكربت خاص بها ضمن الملف package.json.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_56" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="com">// ...</span><span class="pln">
      </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node-dev index.ts"</span><span class="pun">,</span><span class="pln">  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهكذا ستحصل على بيئة تطوير تدعم إعادة التحميل التلقائي للمشروع بتنفيذ الأمر <code>npm run dev</code>.
</p>

<h2>
	التمرينان 9.4 - 9.5
</h2>

<h3>
	9.4 استخدام المكتبة Express
</h3>

<p>
	أضف المكتبة express إلى اعتماديات التطبيق، ثم أنشئ وصلة تخديم endpoint لطلبات HTTP-GET تدعى hello تجيب على الطلب بالعبارة 'Hello FullStack'.
</p>

<p>
	ينبغي أن تُشغّل التطبيق باستخدام الأمر <code>npm start</code> وذلك في بيئة الإنتاج وبالأمر <code>npm run dev</code> في بيئة التطوير التي من المفترض أن تستخدم المكتبة ts-node-dev لتشغيل التطبيق.
</p>

<p>
	استبدل محتوى الملف tsconfig.json بالمحتوى التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_58" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"compilerOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"noImplicitAny"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noImplicitReturns"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strictNullChecks"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strictPropertyInitialization"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"strictBindCallApply"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedLocals"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noUnusedParameters"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"noImplicitThis"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"alwaysStrict"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"esModuleInterop"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"declaration"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	تأكد من عدم وجود أية أخطاء!
</p>

<h3>
	9.5 تطبيق ويب لقياس مؤشر الكتلة BMI
</h3>

<p>
	أضف وصلة تخديم لحاسبة مؤشر الكتلة يمكن استخدامها بإرسال طلبات HTTP-GET إلى وصلة التخديم <code>bmi</code>، بحيث يكون الدخل على شكل معاملات استعلام نصية (<a data-ss1621334558="1" data-ss1621334878="1" href="https://en.wikipedia.org/wiki/Query_string" rel="external nofollow">query string parameters</a>). فلو أردت مثلًا الحصول على مؤشر كتلة شخص طوله 180 ووزنه 72، ستحصل عليه بطلب العنوان <a href="http://localhost:3002/bmi?height=180&amp;weight=72." ipsnoembed="false" rel="external nofollow">http://localhost:3002/bmi?height=180&amp;weight=72.</a>
</p>

<p>
	ستكون الاستجابة بيانات json لها الشكل التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_60" style="">
<span class="pun">{</span><span class="pln">
  weight</span><span class="pun">:</span><span class="pln"> </span><span class="lit">72</span><span class="pun">,</span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">180</span><span class="pun">,</span><span class="pln">
  bmi</span><span class="pun">:</span><span class="pln"> </span><span class="str">"Normal (healthy weight)"</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	اطلع على <a data-ss1621334558="1" data-ss1621334878="1" href="http://expressjs.com/en/5x/api.html#req.query" rel="external nofollow">توثيق express</a> لتعرف آلية الوصول إلى بارامترات الاستعلام.
</p>

<p>
	إن كانت معاملات الطلب من نوع خاطئ أو مفقودة، أجب برمز حالة مناسب ورسالة الخطأ التالية:
</p>

<pre class="ipsCode">
{
  error: "malformatted parameters"
}
</pre>

<p>
	لا تنسخ شيفرة الحاسبة إلى الملف index.ts، بل اجعلها وحدة TS مستقلة يمكن إدراجها ضمن هذا الملف.
</p>

<h2>
	كوابيس استخدام النوع any
</h2>

<p>
	قد نلاحظ بعد أن أكملنا تنفيذ أول وصلة تخديم أننا بالكاد استخدمنا TS في هذا الأمثلة الصغيرة. وقد نلاحظ أيضًا بعض النقاط الخطرة عند تفحص الشيفرة بعناية.
</p>

<p>
	لنضف وصلة تخديم طلبات HTTP-GET تدعى calculate إلى تطبيقنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_63" style="">
<span class="kwd">import</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> calculator </span><span class="pun">}</span><span class="pln"> from </span><span class="str">'./calculator'</span><span class="pln">

</span><span class="com">// ...</span><span class="pln">

app</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(</span><span class="str">'/calculate'</span><span class="pun">,</span><span class="pln"> </span><span class="pun">(</span><span class="pln">req</span><span class="pun">,</span><span class="pln"> res</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">const</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> value1</span><span class="pun">,</span><span class="pln"> value2</span><span class="pun">,</span><span class="pln"> op </span><span class="pun">}</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> req</span><span class="pun">.</span><span class="pln">query

  </span><span class="kwd">const</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> calculator</span><span class="pun">(</span><span class="pln">value1</span><span class="pun">,</span><span class="pln"> value2</span><span class="pun">,</span><span class="pln"> op</span><span class="pun">)</span><span class="pln">
  res</span><span class="pun">.</span><span class="pln">send</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	عندما نمرر مؤشر الفأرة فوق الدالة <code>calculate</code>، ستجد أنها تحمل نوعًا على الرغم من أن الشيفرة ذاتها لا تتضمن أية أنواع.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64474" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/typing_without_types_13.png.9702eb65e27e45b7dcb8fe922d77f952.png" rel=""><img alt="typing_without_types_13.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64474" data-unique="bhuontdal" src="https://academy.hsoub.com/uploads/monthly_2021_04/typing_without_types_13.png.9702eb65e27e45b7dcb8fe922d77f952.png"></a>
</p>

<p>
	وبتمرير مؤشر الفأرة فوق القيم المستخلصة من الطلب، ستظهر مشكلة جديدة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64476" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/variables_type_any_issue_14.png.2eb385ac1415009c2afdd7126b99e0a8.png" rel=""><img alt="variables_type_any_issue_14.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64476" data-unique="546729m5z" src="https://academy.hsoub.com/uploads/monthly_2021_04/variables_type_any_issue_14.png.2eb385ac1415009c2afdd7126b99e0a8.png"></a>
</p>

<p>
	ستحمل جميع المتغيرات النوع any. لن نتفاجأ كثيرًا بما حدث، لأننا في الواقع لم نحدد نوعًا لأي قيمة منها. تُحل المشكلة بطرق عدة، لكن علينا أولًا أن نفهم سبب حدوث هذا السلوك وما الذي جعل القيم من النوع any.
</p>

<p>
	كل متغير في TS لا يملك نوعًا ولا يمكن الاستدلال على نوعه، سيعتبر من النوع any ضمنًا. وهذا النوع هو بمثابة نوع "بديل" ويعني حرفيًا "أيًا كان النوع". ويحدث هذا الأمر كثيرًا عندما ينسى المبرمج أن يحدد نوعًا للقيم التي تعيدها الدالة ولمعاملاتها.
</p>

<p>
	كما يمكن أن نصُرّح بأن نوع المتغيّر هو any. والفرق الوحيد بين التصريح عن هذا النوع أو تضمينه هو في مظهر الشيفرة المكتوبة، فلن يكترث المصرِّف لأي فرق.
</p>

<p>
	لكن سينظر المبرمجون إلى هذا الموضوع بشكل مختلف. فتضمين النوع any يوحي بالمشاكل، لأنه ينتج عادة عن نسيان تحديد نوع المتغير أو المعامل، كما يعني أنك لم تستخدم TS بالطريقة الملائمة.
</p>

<p>
	وهذا هو السبب في وجود قاعدة التهيئة noImplicitAny على مستوى المصرِّف. ومن الأفضل أن تبقيها دائمًا مفعّلة. في الحالات النادرة التي لا تعرف فيها فعلًا نوع المتغيًر، عليك التصريح على أنه من النوع any.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_67" style="">
<span class="kwd">const</span><span class="pln"> a </span><span class="pun">:</span><span class="pln"> any </span><span class="pun">=</span><span class="pln"> </span><span class="com">/* افعل هذا إن كنت لا تعلم حقًا نوع المتغير */</span></pre>

<p>
	لقد فعلنا القاعدة في مثالنا، لماذا إذًا لم يعترض المصرِّف على القيم التي تحمل النوع any ضمنًا؟ يعود السبب إلى الحقل <code>query</code> من كائن <a data-ss1621334558="1" data-ss1621334878="1" href="https://expressjs.com/en/5x/api.html#req" rel="external nofollow">الطلب</a> العائد للمكتبة express، فهو يمتلك النوع any صراحة. وكذلك الأمر بالنسبة للحقل <code>request.body</code> الذي يُستخدم لإرسال المعلومات إلى التطبيق.
</p>

<p>
	هل يمكننا منع المطور من استخدام any نهائيًا؟ لدينا لحسن الحظ طرق أخرى غير استخدام tsconfig.ts لإجبار المطور على اتباع أسلوب محدد في كتابة الشيفرة. إذا يمكننا استخدام المدقق eslint لإدارة أسلوب كتابة الشيفرة. لنثبت eslint إذًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_65" style="">
<span class="pln">npm install </span><span class="pun">--</span><span class="pln">save</span><span class="pun">-</span><span class="pln">dev eslint </span><span class="lit">@typescript</span><span class="pun">-</span><span class="pln">eslint</span><span class="pun">/</span><span class="pln">eslint</span><span class="pun">-</span><span class="pln">plugin </span><span class="lit">@typescript</span><span class="pun">-</span><span class="pln">eslint</span><span class="pun">/</span><span class="pln">parser</span></pre>

<p>
	سنُهيئ المدقق بحيث <a data-ss1621334558="1" data-ss1621334878="1" href="https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-explicit-any.md" rel="external nofollow">يمنع التصريح بالنوع "any"</a>. اكتب القواعد التالية في الملف ذو اللاحقة "eslintrc.":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_69" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"parser"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"@typescript-eslint/parser"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"parserOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"ecmaVersion"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"sourceType"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"module"</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"@typescript-eslint"</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@typescript-eslint/no-explicit-any"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لنكتب أيضًا السكربت lint داخل الملف package.json ليتحقق من وجود ملفات لاحقتها "ts.":
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_71" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
  </span><span class="str">"scripts"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="str">"start"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node index.ts"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"dev"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ts-node-dev index.ts"</span><span class="pun">,</span><span class="pln">
      </span><span class="str">"lint"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"eslint --ext .ts ."</span><span class="pln">      </span><span class="com">//  ...</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="com">// ...</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيعترض المدقق لو حاولنا أن نصرّح عن متغير من النوع any.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64470" data-ss1621334558="1" data-ss1621334878="1" href="https://academy.hsoub.com/uploads/monthly_2021_04/eslint_disallow_any_15.png.2516c016b407fc7dbd688e322e8c77a5.png" rel=""><img alt="eslint_disallow_any_15.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64470" data-unique="en7g1tyqb" src="https://academy.hsoub.com/uploads/monthly_2021_04/eslint_disallow_any_15.png.2516c016b407fc7dbd688e322e8c77a5.png"></a>
</p>

<p>
	ستجد في <a data-ss1621334558="1" data-ss1621334878="1" href="https://github.com/typescript-eslint/typescript-eslint" rel="external nofollow">‎@typescript-eslint</a> الكثير من قواعد المدقق eslint المتعلقة باللغة TS، كما يمكنك استخدام القواعد الأساسية للمدقق في مشاريع هذه اللغة. من الأفضل حاليًا استخدام الإعدادات الموصى بها، ثم يمكننا لاحقًا تعديل القواعد عندما نحتاج إلى ذلك.
</p>

<p>
	وعلينا الانتباه إلى التوصيات المتعلقة بأسلوب كتابة الشيفرة بما يتوافق مع الأسلوب الذي يتطلبه هذا القسم وكذلك وضع فاصلة منقوطة في نهاية كل سطر من أسطر الشيفرة.
</p>

<p>
	سنستخدم حاليًا ملف قواعد المدقق الذي يتضمن ما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_73" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"extends"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
    </span><span class="str">"eslint:recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:@typescript-eslint/recommended"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"plugin:@typescript-eslint/recommended-requiring-type-checking"</span><span class="pln">
  </span><span class="pun">],</span><span class="pln">
  </span><span class="str">"plugins"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"@typescript-eslint"</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"env"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"node"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"es6"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"rules"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"@typescript-eslint/semi"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"error"</span><span class="pun">],</span><span class="pln">
    </span><span class="str">"@typescript-eslint/no-explicit-any"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@typescript-eslint/explicit-function-return-type"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"@typescript-eslint/no-unused-vars"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="str">"error"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="str">"argsIgnorePattern"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"^_"</span><span class="pln"> </span><span class="pun">}],</span><span class="pln">
    </span><span class="str">"no-case-declarations"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
  </span><span class="pun">},</span><span class="pln">
  </span><span class="str">"parser"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"@typescript-eslint/parser"</span><span class="pun">,</span><span class="pln">
  </span><span class="str">"parserOptions"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="str">"project"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"./tsconfig.json"</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هناك بعض الفواصل المنقوطة المفقودة، لكن إضافتها أمر سهل.
</p>

<p>
	والآن علينا إصلاح كل ما يحتاج إلى إصلاح.
</p>

<h2>
	التمرينان 9.6 - 9.7
</h2>

<h3>
	9.6 المدقق ESlint
</h3>

<p>
	هيئ مشروعك ليستخدم الإعدادات السابقة وأصلح كل المشاكل.
</p>

<h3>
	9.7 تطبيق ويب لحساب ساعات التمرين
</h3>

<p>
	أضف وصلة تخديم إلى تطبيقك الذي يحسب ساعات التمرين اليومية. ينبغي أن تستخدم الوصلة لإرسال طلب HTTP-POST إلى وصلة التخديم المقابلة <code>exercises</code> متضمنة معلومات الدخل في جسم الطلب.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_75" style="">
<span class="pun">{</span><span class="pln">
  </span><span class="str">"daily_exercises"</span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2.5</span><span class="pun">],</span><span class="pln">
  </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.5</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الجواب بصيغة json على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9644_77" style="">
<span class="pun">{</span><span class="pln">
    </span><span class="str">"periodLength"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"trainingDays"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"success"</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"rating"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"ratingDescription"</span><span class="pun">:</span><span class="pln"> </span><span class="str">"bad"</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"target"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2.5</span><span class="pun">,</span><span class="pln">
    </span><span class="str">"average"</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1.2142857142857142</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	إن لم يكن جسم الطلب بالتنسيق الصحيح، أعد رمز الحالة المناسب مع رسالة الخطأ هذه:
</p>

<pre class="ipsCode">
{
  error: "parameters missing"
}
</pre>

<p>
	أو هذه:
</p>

<pre class="ipsCode">
{
  error: "malformatted parameters"
}
</pre>

<p>
	بناء على الخطأ. ويحدث الخطأ الثاني إن لم تمتلك القيم المدخلة النوع المناسب، كأن لا تكون أرقامًا أو لا يمكن تحويلها إلى أرقام.
</p>

<p>
	يمكن أن تجد أن التصريح عن متغير بأنه من النوع any مفيدًا في هذا التمرين عندما تتعامل مع البيانات الموجودة ضمن جسم الطلب. ستمنعك طبعًا قواعد تهيئة المدقق، لكن يمكنك أن تلغي تفعيل هذه القاعدة من أجل سطر محدد من الشيفرة بوضع هذا التعليق قبل السطر المطلوب.
</p>

<pre class="ipsCode">
// eslint-disable-next-line @typescript-eslint/no-explicit-any
</pre>

<p>
	انتبه بأنك ستحتاج إلى تهيئة صحيحة لتتمكن من الاحتفاظ ببيانات جسم الطلب. راجع القسم 3.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a data-ss1621334558="1" data-ss1621334878="1" href="https://fullstackopen.com/en/part9/first_steps_with_typescript" rel="external nofollow">First steps with TypeScript</a> من سلسلة <a data-ss1621334558="1" data-ss1621334878="1" href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1215</guid><pubDate>Sat, 15 May 2021 09:05:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; TypeScript</title><link>https://academy.hsoub.com/programming/javascript/typescript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-typescript-r1214/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_04/608298bf98af5_--TypeScript.png.902b4bb35006ce1e5940eaa8dc6d2dce.png" /></p>

<p>
	TypeScript هي لغة برمجة مصممة لتنفيذ مشاريع JavaScript ضخمة، صممتها Microsoft. فقد بُنيت على سبيل المثال برنامج مثل Azure Management Portal الذي يبلغ عدد أسطر شيفرته 1.2 مليون، وبرنامج Visiual Studio Code الذي يبلغ عدد أسطر شيفرته 300 ألف باستخدام TypeScript. تقدم TypeScript ميزات عديدة لدعم مشاريع JavaScript الضخمة مثل أدوات تطوير أفضل وتحليل شيفرة ساكنة والتحقق من الأنواع عند الترجمة والتوثيق على مستوى الشيفرة.
</p>

<h2>
	المبدأ الرئيسي
</h2>

<p>
	تمثل اللغة TypeScript مجموعة مطوّرة من تعليمات JavaScript قادرة على تمييز الأنواع وتترجم عادة إلى شيفرة JavaScript صرفة. ويمكن للمطور أن يحدد إصدار الشيفرة الناتجة طالما أن إصدار ECMAScript هو الإصدار 3 أو أحدث. ويعني أنّ هذه اللغة مجموعة مطوّرة من تعليمات JavaScript أنها تتضمن كل ميزات JavaScript بالإضافة إلى ميزات خاصة بها. وتعتبر كل شيفرات JavaScript شيفرات TypeScript صحيحة.
</p>

<p>
	تتألف TypeScript من ثلاثة أقسام منفصلة لكنها متكاملة مع بعضها:
</p>

<ul>
<li>
		اللغة
	</li>
	<li>
		المصرِّف
	</li>
	<li>
		خدمة اللغة
	</li>
</ul>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="64463" href="https://academy.hsoub.com/uploads/monthly_2021_04/typescript_parts_01.png.7f2b3d1727ef6454734e04186b3af238.png" rel=""><img alt="typescript_parts_01.png" class="ipsImage ipsImage_thumbnailed" data-fileid="64463" data-unique="z561ots82" src="https://academy.hsoub.com/uploads/monthly_2021_04/typescript_parts_01.thumb.png.48fa69fa7ef52ff72ea1f42ad6dc89fa.png"></a>
</p>

<p>
	تتألف اللغة من القواعد والكلمات المحجوزة (تعليمات) ومسجلات الأنواع Type annotations وتتشابه قواعدها مع مثيلاتها في JavaScript لكنها ليست متماثلة. وأكثر ما يتعامل معه المبرمجون من تلك الأقسام هي اللغة.
</p>

<p>
	تنحصر مهمة المصرِّف في محو المعلومات المتعلقة بالنوع بالإضافة إلى التحويلات على الشيفرة. إذ تمكن عملية تحويل الشيفرة من نقل شيفرة TypeScript إلى شيفرة JavaScript قابلة للتنفيذ. يزيل المصرِّف كل ما يتعلق بالأنواع أثناء الترجمة، وبالتالي لا تميز هذه اللغة الأنواع بشكل فعلي قبل الترجمة.
</p>

<p>
	تعني عملية التصريف بالمعنى المتعارف عليه، تحويل الشيفرة من الشكل الذي يمكن للإنسان قراءته وفهمه إلى الشكل الذي تفهمه الآلة. أما عملية الترجمة في TypeScript فهي عملية تحويل الشيفرة من شكل يفهمه الإنسان إلى شكل آخر يفهمه الإنسان أيضًا، لذا من الأنسب أن تسمى هذه العملية بالنقل Transpilling. لكن مصطلح الصريف هو الأشيع في هذا المضمار وسنستخدمه نحن بدورنا.
</p>

<p>
	ينفذ المصرِّف أيضًا عملية تحليل الشيفرة ما قبل التنفيذ. إذ يمكنه إظهار رسائل التحذير والخطأ إن كان هناك سبب لذلك، كما يمكن أن يُهيَّئ لتنفيذ مهام إضافية كضم الشيفرة الناتجة في ملف واحد.
</p>

<p>
	تجمع خدمة اللغة معلومات عن الأنواع الموجودة في الشيفرة المصدرية. وبالتالي ستتمكن أدوات التطوير من استخدامها في تقديم ميزة إكمال الشيفرة في بيئات التطوير وطباعة التلميحات وتقديم اقتراحات لإعادة كتابة أجزاء من الشيفرة.
</p>

<h2>
	الميزات الرئيسية للغة TypeScript
</h2>

<p>
	سنقدم تاليًا وصفًا لبعض ميزات اللغة TypeScript. والغاية من ذلك تزويدك بالأساسيات التي تقدمها اللغة وميزاتها، وذلك للتعامل مع الأفكار التي سنراها تباعًا في المنهاج.
</p>

<h3>
	مسجلات الأنواع
</h3>

<p>
	وهي طريقة خفيفة في TypeScript لتسجيل الأنواع التي نريد أن تمرر أو تعاد من الدوال أو أنواع المتغيرات. فلقد عرفنا في المثال التالي على سبيل المثال الدالة <code>birthdayGreeter</code> التي تقبل معاملين أحدهما من النوع string، والآخر من النوع number، وستعيد قيمة من النوع string.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2624_6" style="">
<span class="kwd">const</span><span class="pln"> birthdayGreeter </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">,</span><span class="pln"> age</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">):</span><span class="pln"> string </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">`</span><span class="typ">Happy</span><span class="pln"> birthday $</span><span class="pun">{</span><span class="pln">name</span><span class="pun">},</span><span class="pln"> you are now $</span><span class="pun">{</span><span class="pln">age</span><span class="pun">}</span><span class="pln"> years old</span><span class="pun">!`;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> birthdayHero </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Jane User"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> age </span><span class="pun">=</span><span class="pln"> </span><span class="lit">22</span><span class="pun">;</span><span class="pln">

console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">birthdayGreeter</span><span class="pun">(</span><span class="pln">birthdayHero</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">));</span></pre>

<h3>
	نظام الخصائص المعرفة للأنواع
</h3>

<p>
	تستخدم اللغة TypeScript الخصائص المعرفة للأنواع structural typing. ويعتبر عنصران في هذا النظام متوافقان إن كان لكل ميزة في النوع الأول ميزة تماثلها تمامًا في النوع الثاني. ويعتبر النوعان متطابقان إذا كانا متوافقان مع بعضهما.
</p>

<h3>
	الاستدلال على النوع
</h3>

<p>
	يحاول المصرِّف أن يستدل على نوع المعلومة إن لم يحدد لها نوع. إذ يمكن الاستدلال على نوع المتغير بناء على القيمة التي أسندت له. تحدث هذه العملية عند تهيئة المتغيرات والأعضاء، وعند إسناد القيم الافتراضية للمعاملات، وعند تحديد القيمة التي تعيدها دالة.
</p>

<p>
	لنتأمل على سبيل المثال الدالة <code>Add</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_1381_6" style="">
<span class="kwd">const</span><span class="pln"> add </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">:</span><span class="pln"> number</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="com">/* تستخدم القيمة المعادة لتحديد نوع القيمة التي تعيدها الدالة*/</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يستدل المصرِّف على نوع القيمة المعادة للدالة بتعقب الشيفرة حتى الوصول إلى عبارة <code>return</code>. تعيد هذه العبارة مجموع المعاملين <code>a</code> و<code>b</code>. وكما نرى فكلا المعاملين من النوع number وهكذا سيستدل المصرِّف على أن القيمة التي تعيدها الدالة من النوع number.
</p>

<p>
	وكمثال أكثر تعقيدًا، لنتأمل الشيفرة التالية (قد يكون المثال صعب الفهم قليلًا إن لم تكن قد استخدمت TypeScript مسبقًا. يمكنك تخطي هذا المثال حاليًا.)
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2624_12" style="">
<span class="pln">type </span><span class="typ">CallsFunction</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">callback</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">result</span><span class="pun">:</span><span class="pln"> string</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> any</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="kwd">void</span><span class="pun">;</span><span class="pln">

</span><span class="kwd">const</span><span class="pln"> func</span><span class="pun">:</span><span class="pln"> </span><span class="typ">CallsFunction</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">cb</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  cb</span><span class="pun">(</span><span class="str">'done'</span><span class="pun">);</span><span class="pln">
  cb</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

func</span><span class="pun">((</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	بداية نجد تصريحًا لاسم نوع مستعار <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-aliases" rel="external nofollow">type alias</a> يدعى <code>CallsFunction</code>. يُمثل نوع دالة تقبل معاملًا واحدًا <code>callback</code> يمثِّل بدوره دالة تتلقى معاملًا من النوع "string" وتعيد قيمة من النوع <a href="http://www.typescriptlang.org/docs/handbook/basic-types.html#any" rel="external nofollow">any</a>. وكما سنرى لاحقًا فالنوع any هو شكل من أشكال الحروف البديلة wildcards والتي يمكن أن تحل محل أي نوع.
</p>

<p>
	بعد ذلك نعرّف الدالة <code>func</code> من النوع <code>CallsFunction</code>. يمكننا أن نستدل من نوع الدالة بأن معاملها الدالة <code>cb</code> ستقبل فقط معاملًا من النوع string.ولتوضيح ذلك سنورد مثالًا آخر تُستدعى فيه دالة كمعامل لكن بقيمة من النوع number، وسيسبب هذا الاستدعاء خطأً في TypeScript.
</p>

<p>
	وأخيرًا نستدعي الدالة <code>func</code> بعد أن نمرر إليها الدالة التالية كمعامل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2624_14" style="">
<span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وعلى الرغم من عدم تحديد أنواع معاملات الدالة، يمكننا الاستدلال من سياق الاستدعاء أن المعامل <code>result</code> من النوع String.
</p>

<h3>
	إزالة الأنواع
</h3>

<p>
	تزيل TypeScript جميع الأنواع التي يبنيها نظام تحديد الأنواع أثناء الترجمة:
</p>

<p>
	فلو كانت الشيفرة قبل الترجمة كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2624_17" style="">
<span class="pln">let x</span><span class="pun">:</span><span class="pln"> </span><span class="typ">SomeType</span><span class="pun">;</span></pre>

<p>
	ستكون بعد الترجمة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2624_19" style="">
<span class="pln">let x</span><span class="pun">;</span></pre>

<p>
	ويعني هذا عدم وجود أية معلومات عن الانواع أثناء التنفيذ، فلا يشير أي شيء على أن متغيرًا X على سبيل المثال قد عُرِّف أنه من نوع ما.
</p>

<p>
	سيكون النقص في المعلومات عن الأنواع في زمن التنفيذ مفاجئًا للمبرمجين الذين اعتادوا على استخدام تعليمات التحقق Reflection وغيرها من أنظمة إظهار البيانات الوصفية.
</p>

<h2>
	هل علينا فعلا استعمال TypeScript؟
</h2>

<p>
	إن كنت من متابعي المنتديات البرمجية على الانترنت، ستجد تضاربًا في الآراء الموافقة والمعارضة لاستخدام هذه اللغة.
</p>

<p>
	والحقيقة أنّ مدى حاجتك لاستخدام الدوال التي تقدمها TypeScript هي من يحدد وجهة نظرك. سنعرض على أية حال بعض الأسباب التي قد تجعل استخدام هذه اللغة مفيدًا.
</p>

<p>
	أولًا: ستقدم ميزة التحقق من الأنواع وميزة التحليل الساكن للشيفرة (قبل الترجمة والتنفيذ). كما يمكننا أن نطلب قيمًا من نوع محدد وأن نتلقى تحذيرات من المصرِّف عندما نستخدم هذه القيم بشكل خاطئ. سيقلل هذا الأمر الأخطاء التي تحصل وقت التنفيذ، كما يمكن أن يقلل من عدد اختبارات الأجزاء unit tests التي يحتاجها التطبيق وخاصة ما يتعلق باختبارات الأنواع الصرفة pure types. ولا تحذرك عملية التحليل الساكن للشيفرة من الاستخدام الخاطئ للأنواع وحسب، بل تشير إلى الأخطاء الأخرى ككتابة اسم المتغير أو الدالة بشكل خاطئ أو استخدام المتغير خارج المجال المعرّف ضمنه.
</p>

<p>
	ثانيًا: يمكن لميزة تسجيل الأنواع أن تعمل كشكل من أشكال التوثيق على مستوى الشيفرة. إذ يمكنك أن تتحقق من خلال بصمة الدالة signature من الأنواع التي تتلقاها الدالة والأنواع التي ستعيدها. سيبقى هذا الشكل من التوثيق محدّثًا أثناء تقدم العمل، وسيسهّل ذلك التعامل مع مشاريع جاهزة وخاصة للمبرمجين الجدد. كما ستساعد كثيرًا عند العودة إلى مشاريع قديمة.
</p>

<p>
	يمكن إعادة استخدام الأنواع في أي مكان من الشيفرة، وستنتقل أية تغييرات على تعريف النوع إلى أي مكان استخدم فيه هذا النوع. وقد يجادل البعض بأن استخدام <a href="https://jsdoc.app/about-getting-started.html" rel="external nofollow">JSDoc</a> سينجز التوثيق على مستوى الشيفرة بشكل مماثل، لكنه لا يرتبط بالشيفرة بشكل وثيق كما تفعل أنواع TypeScript، وقد يسبب هذا خللًا في تزامن عرض المعلومات، بالإضافة إلى أنها أطول.
</p>

<p>
	ثالثًا: ستقدم بيئة عمل اللغة ميزة إكمال الشيفرة بشكل أفضل لأنها تعلم تمامًا نوع البيانات التي تعالجها.
</p>

<p>
	وتعتبر الميزات الثلاث السابقة مفيدة للغاية عند إعادة كتابة الشيفرة. فسيحذرك التحليل الساكن للشيفرة من الأخطاء في شيفرتك، وسيرشدك معالج إكمال الشيفرة إلى الخصائص التي يقدمها المتغير أو الكائن أو حتى خيارات لإعادة كتابة الشيفرة بشكل أنسب، وسيساعدك التوثيق على مستوى الشيفرة في فهم الشيفرة المكتوبة. وبهذه المساعدة التي تقدمها لك بيئة عمل هذه اللغة، سيكون من السهل استخدام الميزات الأحدث من لغة JavaScript وفي أية مرحلة تقريبًا بمجرد تغيير إعدادات التهيئة.
</p>

<h2>
	ما الأمور التي لا يمكن للغة TypeScript أن توفرها لك؟
</h2>

<p>
	لقد ذكرنا سابقًا أن تسجيل الأنواع والتحقق منها فقط في مراحل ما قبل التنفيذ. فحتى لو لم يشر المصرِّف إلى أخطاء فقط تحدث الأخطاء أثناء التنفيذ. تحدث أخطاء زمن التنفيذ بشكل متكرر عند التعامل مع مصدر دخل خارجي كالبيانات المستقبلة كطلب عبر شبكة.
</p>

<p>
	وضعنا أخيرًا قائمة بالمشاكل التي قد تواجهنا عند استخدام TypeScript، ويجب الانتباه إليها:
</p>

<h3>
	الأنواع غير المكتملة أو الخاطئة أو المفقودة التي مصدرها مكتبات خارجية
</h3>

<p>
	قد تجد في بعض المكتبات الخارجية أنواعًا غير معرّفة أو ذات تعريف خاطئ بشكل أو بآخر. والسبب المرجح أنّ المكتبة لم تُكتَب بلغة Typescript، وأنّ المبرمج الذي صرّح عن النوع يدويًا قد ارتكب خطأً. عليك في هذه الحال كتابة التصريح عن النوع يدويًا بنفسك. لكن هناك فرصة كبيرة أن يكون أحدهم قد فعل ذلك مسبقًا عوضًا عنك، تحقق من موقع <a href="https://definitelytyped.org/" rel="external nofollow">DefinitelyTyped</a> أو <a href="https://github.com/DefinitelyTyped/DefinitelyTyped" rel="external nofollow">صفحة GitHub</a> الخاصة بهذا الموقع أولًا. وهذان المصدران هما الأكثر شعبية لإيجاد ملفات تعريف الأنواع. في حال لم يحالفك الحظ، لابدّ أن تبدأ من الصفر بقراءة توثيق TypeScript بما يخص تعريف الأنواع.
</p>

<h3>
	قد يحتاج الاستدلال على النوع إلى بعض المساعدة
</h3>

<p>
	إن الاستدلال على النوع في هذه اللغة جيد جدًا لكنه ليس مثاليًا.
</p>

<p>
	قد تعتقد أحيانًا أنك صرحت عن نوع بشكل مثالي، لكن المصرِّف يحذرك بشكل مستمر من أن خاصية محددة غير موجودة أو أنّ التصريح بهذه الطريقة غير مسموح. عليك في حالات كهذه مساعدة المصرِّف بتنفيذ عملية تحقق إضافية من النوع الذي صرحت عنه، وخاصة فيما يتعلق بالتحويل بين الأنواع type casting أو حاميات الأنواع type gaurds.
</p>

<p>
	عند التحويل بين الأنواع أو عند استخدام الحاميات فأنت بذلك تضمن للمصرِّف أن القيمة التي وضعتها هي بالتأكيد من النوع المصرح عنه وهذا مصدر للأخطاء. ربما عليك الاطلاع على التوثيق فيما يتعلق <a href="https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types" rel="external nofollow">بحاميات الأنواع</a> أو مؤكدات الأنواع <a href="https://www.typescriptlang.org/docs/handbook/basic-types.html#type-assertions" rel="external nofollow">Type Assertions</a>.
</p>

<h3>
	أخطاء الأنواع الغامضة
</h3>

<p>
	من الصعب أحيانًا فهم طبيعة الخطأ الذي يعطيه نظام تحديد الأنواع، وخاصة إن استخدمت أنواع معقدة. وكقاعدة أساسية، ستحمل لك رسائل خطأ TypeScript المعلومات الأكثر أهمية في نهاية الرسالة. فعندما تظهر لك رسالة طويلة مزعجة، ابدأ بالقراءة من آخر الرسالة.
</p>

<p>
	ترجمة -وبتصرف- للفصل <a href="https://fullstackopen.com/en/part9/background_and_introduction" rel="external nofollow">Background and introduction</a> من سلسلة <a href="https://fullstackopen.com/en/" rel="external nofollow">Deep Dive Into Modern Web Development</a>
</p>
]]></description><guid isPermaLink="false">1214</guid><pubDate>Wed, 12 May 2021 09:09:00 +0000</pubDate></item><item><title>[&#x641;&#x64A;&#x62F;&#x64A;&#x648;] &#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; TypeScript</title><link>https://academy.hsoub.com/programming/javascript/typescript/%D9%81%D9%8A%D8%AF%D9%8A%D9%88-%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-typescript-r660/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2019_03/typescript.png.11d9e0f6bf39bf31001209f769672e66.png" /></p>

<p>
	<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/Jvi6dTqFcj4" width="700"></iframe>
</p>

<p>
	نشرح في هذا الفيديو طريقة تثبيت TypeScript وإعدادها لتستطيع الاستفادة منها في تطوير تطبيقاتك.
</p>

<p>
	يمكنك الاستعانة <a href="https://wiki.hsoub.com/TypeScript" rel="external">بتوثيق TypeScript في موسوعة حسوب</a> المتاح باللغة العربية.
</p>
]]></description><guid isPermaLink="false">660</guid><pubDate>Sat, 09 Mar 2019 15:14:00 +0000</pubDate></item></channel></rss>
