InversifyJS: حاوية IoC قوية لـ TypeScript
\n\nInversifyJS هي حاوية IoC (عكس التحكم) خفيفة الوزن ولكنها قوية للغاية لتطبيقات TypeScript و JavaScript. وهي تنفذ نمط حقن التبعية (DI)، مما يسمح للمطورين بإنشاء أنظمة ضعيفة الاقتران وقابلة للاختبار وقابلة للتوسع. تستخدم المكتبة بشكل فعال إمكانيات TypeScript (الديكورات والأنواع) لضمان كتابة صارمة وسهولة في التطوير.
\n\nتعتبر InversifyJS مثالية لتطبيقات الخادم على Node.js، وكذلك للمشاريع العميلة مع أطر عمل مثل Angular أو React أو Vue. في هذا الاستعراض، سنقوم بتحليل المفاهيم الأساسية ونوضح كيفية البدء بسرعة.
\n\nالمفاهيم الأساسية لـ InversifyJS
\n\nقبل كتابة الكود، من المهم فهم الكيانات الرئيسية الثلاثة للمكتبة:
\n\n- \n
- الحاوية (Container) — الكائن المركزي الذي يدير جميع التبعيات. تقوم بتسجيل التجريدات وتطبيقاتها فيه. \n
- معرفات الخدمة (Service Identifiers) — مفاتيح فريدة تستخدمها الحاوية للعثور على التطبيق المطلوب. يمكن أن تكون سلاسل نصية أو رموزًا أو فئات. \n
- الديكورات —
@injectable()و@inject()— تشير إلى TypeScript أن الفئة يمكن حقنها، وما هي التبعيات التي تحتاجها. \n
التثبيت والإعداد
\n\nللبدء، قم بتثبيت InversifyJS وتبعياتها المطبعية:
\n\nnpm install inversify reflect-metadata --save\nnpm install --save-dev @types/node\n\nثم أضف خيارين إجباريين إلى tsconfig.json:
{\n "compilerOptions": {\n "emitDecoratorMetadata": true,\n "experimentalDecorators": true,\n "types": ["reflect-metadata"]\n }\n}\n\nبعد ذلك، قم باستيراد reflect-metadata في الملف الرئيسي للتطبيق (عادةً index.ts أو main.ts):
import "reflect-metadata";\n\nالمثال الأول: خدمة بسيطة
\n\nلنقم بإنشاء واجهة وتطبيقها. لاحظ الديكور @injectable():
// interfaces/IWarrior.ts\nexport interface IWarrior {\n fight(): string;\n}\n\n// entities/Warrior.ts\nimport { injectable } from "inversify";\n\n@injectable()\nexport class Warrior implements IWarrior {\n fight(): string {\n return "Warrior attacks with sword!";\n }\n}\n\nالآن، لنقم بتسجيل هذا الارتباط في الحاوية والحصول على مثيل:
\n\nimport { Container } from "inversify";\nimport { IWarrior } from "./interfaces/IWarrior";\nimport { Warrior } from "./entities/Warrior";\n\nconst container = new Container();\n\n// تسجيل التجريد مع تطبيقه\ncontainer.bind<IWarrior>("IWarrior").to(Warrior);\n\n// الحصول على مثيل\nconst warrior = container.get<IWarrior>("IWarrior");\nconsole.log(warrior.fight()); // "Warrior attacks with sword!"\n\nحقن التبعيات عبر المُنشئ
\n\nتتجلى القوة الحقيقية لحقن التبعية عندما تعتمد فئة على أخرى. استخدم الديكور @inject():
// interfaces/IWeapon.ts\nexport interface IWeapon {\n use(): string;\n}\n\n// entities/Sword.ts\nimport { injectable } from "inversify";\n\n@injectable()\nexport class Sword implements IWeapon {\n use(): string {\n return "Swing sword!";\n }\n}\n\n// entities/Knight.ts\nimport { injectable, inject } from "inversify";\nimport { IWarrior } from "../interfaces/IWarrior";\nimport { IWeapon } from "../interfaces/IWeapon";\n\n@injectable()\nexport class Knight implements IWarrior {\n private _weapon: IWeapon;\n\n constructor(@inject("IWeapon") weapon: IWeapon) {\n this._weapon = weapon;\n }\n\n fight(): string {\n return this._weapon.use() + " The knight fights!";\n }\n}\n\nتسجيل