العربية

أطلق العنان لقوة دمج فضاءات الأسماء في TypeScript! يستكشف هذا الدليل أنماط تصريح الوحدات المتقدمة للنمطية، والقابلية للتوسعة، وكتابة كود أنظف، مع أمثلة عملية للمطورين العالميين.

دمج فضاءات الأسماء في TypeScript: أنماط متقدمة لتصريح الوحدات

تقدم TypeScript ميزات قوية لهيكلة وتنظيم الكود الخاص بك. إحدى هذه الميزات هي دمج فضاءات الأسماء (namespace merging)، والتي تسمح لك بتعريف فضاءات أسماء متعددة بنفس الاسم، وسيقوم TypeScript تلقائيًا بدمج تصريحاتها في فضاء أسماء واحد. هذه الإمكانية مفيدة بشكل خاص لتوسيع المكتبات الحالية، وإنشاء تطبيقات نمطية، وإدارة تعريفات الأنواع المعقدة. سيتعمق هذا الدليل في الأنماط المتقدمة لاستخدام دمج فضاءات الأسماء، مما يمكّنك من كتابة كود TypeScript أنظف وأكثر قابلية للصيانة.

فهم فضاءات الأسماء والوحدات

قبل الغوص في دمج فضاءات الأسماء، من الضروري فهم المفاهيم الأساسية لفضاءات الأسماء (namespaces) والوحدات (modules) في TypeScript. على الرغم من أن كليهما يوفر آليات لتنظيم الكود، إلا أنهما يختلفان بشكل كبير في نطاقهما واستخدامهما.

فضاءات الأسماء (الوحدات الداخلية)

فضاءات الأسماء هي بنية خاصة بـ TypeScript لتجميع الكود المرتبط معًا. إنها تنشئ بشكل أساسي حاويات مسماة لوظائفك وفئاتك وواجهاتك ومتغيراتك. تُستخدم فضاءات الأسماء بشكل أساسي لتنظيم الكود الداخلي داخل مشروع TypeScript واحد. ومع ذلك، مع ظهور وحدات ES، أصبحت فضاءات الأسماء أقل تفضيلاً بشكل عام للمشاريع الجديدة ما لم تكن بحاجة إلى التوافق مع قواعد الكود القديمة أو سيناريوهات تعزيز النطاق العام المحددة.

مثال:


namespace Geometry {
  export interface Shape {
    getArea(): number;
  }

  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

const myCircle = new Geometry.Circle(5);
console.log(myCircle.getArea()); // Output: 78.53981633974483

الوحدات (الوحدات الخارجية)

الوحدات، من ناحية أخرى، هي طريقة موحدة لتنظيم الكود، تحددها وحدات ES (وحدات ECMAScript) و CommonJS. الوحدات لها نطاقها الخاص وتقوم باستيراد وتصدير القيم بشكل صريح، مما يجعلها مثالية لإنشاء مكونات ومكتبات قابلة لإعادة الاستخدام. وحدات ES هي المعيار في تطوير JavaScript و TypeScript الحديث.

مثال:


// circle.ts
export interface Shape {
  getArea(): number;
}

export class Circle implements Shape {
  constructor(public radius: number) {}

  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

// app.ts
import { Circle } from './circle';

const myCircle = new Circle(5);
console.log(myCircle.getArea());

قوة دمج فضاءات الأسماء

يسمح لك دمج فضاءات الأسماء بتعريف كتل متعددة من الكود بنفس اسم فضاء الأسماء. يقوم TypeScript بذكاء بدمج هذه التصريحات في فضاء أسماء واحد في وقت الترجمة. هذه الإمكانية لا تقدر بثمن من أجل:

أنماط متقدمة لتصريح الوحدات مع دمج فضاءات الأسماء

دعنا نستكشف بعض الأنماط المتقدمة لاستخدام دمج فضاءات الأسماء في مشاريع TypeScript الخاصة بك.

1. توسيع المكتبات الحالية باستخدام التصريحات المحيطة

واحدة من أكثر حالات الاستخدام شيوعًا لدمج فضاءات الأسماء هي توسيع مكتبات JavaScript الحالية بتعريفات أنواع TypeScript. تخيل أنك تستخدم مكتبة JavaScript تسمى `my-library` لا تدعم TypeScript رسميًا. يمكنك إنشاء ملف تصريح محيط (مثل `my-library.d.ts`) لتحديد الأنواع لهذه المكتبة.

مثال:


// my-library.d.ts
declare namespace MyLibrary {
  interface Options {
    apiKey: string;
    timeout?: number;
  }

  function initialize(options: Options): void;
  function fetchData(endpoint: string): Promise;
}

الآن، يمكنك استخدام فضاء الأسماء `MyLibrary` في كود TypeScript الخاص بك مع أمان الأنواع:


// app.ts
MyLibrary.initialize({
  apiKey: 'YOUR_API_KEY',
  timeout: 5000,
});

MyLibrary.fetchData('/api/data')
  .then(data => {
    console.log(data);
  });

إذا كنت بحاجة إلى إضافة المزيد من الوظائف إلى تعريفات أنواع `MyLibrary` لاحقًا، يمكنك ببساطة إنشاء ملف `my-library.d.ts` آخر أو الإضافة إلى الملف الحالي:


// my-library.d.ts

declare namespace MyLibrary {
  interface Options {
    apiKey: string;
    timeout?: number;
  }

  function initialize(options: Options): void;
  function fetchData(endpoint: string): Promise;

  // Add a new function to the MyLibrary namespace
  function processData(data: any): any;
}

سيقوم TypeScript تلقائيًا بدمج هذه التصريحات، مما يسمح لك باستخدام الدالة الجديدة `processData`.

2. تعزيز الكائنات العامة

في بعض الأحيان، قد ترغب في إضافة خصائص أو طرق إلى الكائنات العامة الموجودة مثل `String` أو `Number` أو `Array`. يسمح لك دمج فضاءات الأسماء بالقيام بذلك بأمان ومع التحقق من الأنواع.

مثال:


// string.extensions.d.ts
declare global {
  interface String {
    reverse(): string;
  }
}

String.prototype.reverse = function() {
  return this.split('').reverse().join('');
};

console.log('hello'.reverse()); // Output: olleh

في هذا المثال، نضيف دالة `reverse` إلى النموذج الأولي لـ `String`. تخبر الصيغة `declare global` TypeScript بأننا نعدل كائنًا عامًا. من المهم ملاحظة أنه على الرغم من أن هذا ممكن، إلا أن تعزيز الكائنات العامة يمكن أن يؤدي أحيانًا إلى تعارضات مع مكتبات أخرى أو معايير JavaScript المستقبلية. استخدم هذه التقنية بحكمة.

اعتبارات التدويل: عند تعزيز الكائنات العامة، خاصةً بالطرق التي تتعامل مع السلاسل النصية أو الأرقام، كن على دراية بالتدويل. تعمل دالة `reverse` أعلاه مع سلاسل ASCII الأساسية، لكنها قد لا تكون مناسبة للغات ذات مجموعات الأحرف المعقدة أو اتجاه الكتابة من اليمين إلى اليسار. فكر في استخدام مكتبات مثل `Intl` لمعالجة السلاسل النصية المتوافقة مع الإعدادات المحلية.

3. نمطية فضاءات الأسماء الكبيرة

عند العمل مع فضاءات أسماء كبيرة ومعقدة، من المفيد تقسيمها إلى ملفات أصغر وأكثر قابلية للإدارة. دمج فضاءات الأسماء يجعل هذا الأمر سهلاً.

مثال:


// geometry.ts
namespace Geometry {
  export interface Shape {
    getArea(): number;
  }
}

// circle.ts
namespace Geometry {
  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

// rectangle.ts
namespace Geometry {
  export class Rectangle implements Shape {
    constructor(public width: number, public height: number) {}

    getArea(): number {
      return this.width * this.height;
    }
  }
}

// app.ts
/// 
/// 
/// 

const myCircle = new Geometry.Circle(5);
const myRectangle = new Geometry.Rectangle(10, 5);

console.log(myCircle.getArea()); // Output: 78.53981633974483
console.log(myRectangle.getArea()); // Output: 50

في هذا المثال، قمنا بتقسيم فضاء الأسماء `Geometry` إلى ثلاثة ملفات: `geometry.ts`، `circle.ts`، و `rectangle.ts`. يساهم كل ملف في فضاء الأسماء `Geometry`، ويقوم TypeScript بدمجها معًا. لاحظ استخدام توجيهات `/// `. على الرغم من أنها تعمل، إلا أنها نهج أقدم، ويفضل عمومًا استخدام وحدات ES في مشاريع TypeScript الحديثة، حتى عند استخدام فضاءات الأسماء.

النهج الحديث للوحدات (المفضل):


// geometry.ts
export namespace Geometry {
  export interface Shape {
    getArea(): number;
  }
}

// circle.ts
import { Geometry } from './geometry';

export namespace Geometry {
  export class Circle implements Shape {
    constructor(public radius: number) {}

    getArea(): number {
      return Math.PI * this.radius * this.radius;
    }
  }
}

// rectangle.ts
import { Geometry } from './geometry';

export namespace Geometry {
  export class Rectangle implements Shape {
    constructor(public width: number, public height: number) {}

    getArea(): number {
      return this.width * this.height;
    }
  }
}

// app.ts
import { Geometry } from './geometry';
const myCircle = new Geometry.Circle(5);
const myRectangle = new Geometry.Rectangle(10, 5);

console.log(myCircle.getArea());
console.log(myRectangle.getArea());

يستخدم هذا النهج وحدات ES جنبًا إلى جنب مع فضاءات الأسماء، مما يوفر نمطية أفضل وتوافقًا مع أدوات JavaScript الحديثة.

4. استخدام دمج فضاءات الأسماء مع تعزيز الواجهات

غالبًا ما يتم دمج فضاءات الأسماء مع تعزيز الواجهات (interface augmentation) لتوسيع قدرات الأنواع الحالية. يتيح لك هذا إضافة خصائص أو طرق جديدة إلى الواجهات المحددة في مكتبات أو وحدات أخرى.

مثال:


// user.ts
interface User {
  id: number;
  name: string;
}

// user.extensions.ts
namespace User {
  export interface User {
    email: string;
  }
}

// app.ts
import { User } from './user'; // Assuming user.ts exports the User interface
import './user.extensions'; // Import for side-effect: augment the User interface

const myUser: User = {
  id: 123,
  name: 'John Doe',
  email: 'john.doe@example.com',
};

console.log(myUser.name);
console.log(myUser.email);

في هذا المثال، نضيف خاصية `email` إلى الواجهة `User` باستخدام دمج فضاءات الأسماء وتعزيز الواجهات. يقوم ملف `user.extensions.ts` بتعزيز الواجهة `User`. لاحظ استيراد `./user.extensions` في `app.ts`. هذا الاستيراد هو فقط لتأثيره الجانبي المتمثل في تعزيز الواجهة `User`. بدون هذا الاستيراد، لن يتم تفعيل التعزيز.

أفضل الممارسات لدمج فضاءات الأسماء

بينما يعد دمج فضاءات الأسماء ميزة قوية، فمن الضروري استخدامه بحكمة واتباع أفضل الممارسات لتجنب المشكلات المحتملة:

الاعتبارات العالمية

عند تطوير تطبيقات لجمهور عالمي، ضع الاعتبارات التالية في اعتبارك عند استخدام دمج فضاءات الأسماء:

مثال على التوطين باستخدام `Intl` (واجهة برمجة تطبيقات التدويل):


// number.extensions.d.ts
declare global {
  interface Number {
    toCurrencyString(locale: string, currency: string): string;
  }
}

Number.prototype.toCurrencyString = function(locale: string, currency: string) {
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency,
  }).format(this);
};

const price = 1234.56;

console.log(price.toCurrencyString('en-US', 'USD')); // Output: $1,234.56
console.log(price.toCurrencyString('de-DE', 'EUR')); // Output: 1.234,56 €
console.log(price.toCurrencyString('ja-JP', 'JPY')); // Output: ¥1,235

يوضح هذا المثال كيفية إضافة دالة `toCurrencyString` إلى النموذج الأولي لـ `Number` باستخدام واجهة برمجة التطبيقات `Intl.NumberFormat`، والتي تسمح لك بتنسيق الأرقام وفقًا للغات والعملات المختلفة.

الخاتمة

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

دمج فضاءات الأسماء في TypeScript: أنماط متقدمة لتصريح الوحدات | MLOG