تايب سكريبت - إضافة دوال إلى تعداد


هل من الممكن إضافة وظائف إلى نوع Enum في TypeScript؟

على سبيل المثال:

enum Mode {
    landscape,
    portrait,

    // the dream...
    toString() { console.log(this); } 
}

أو :

class ModeExtension {
    public toString = () => console.log(this);
}

enum Mode extends ModeExtension {
    landscape,
    portrait,
}

بالطبع ستحتوي دالة toString() على شيء مثل switch لكن سيناريو الاستخدام سيكون على النحو التالي:

class Device {
    constructor(public mode:Mode) {
        console.log(this.mode.toString());
    }
}

أفهم لماذا قد يكون تمديد enum أمرًا غريبًا، فقط أتساءل إذا كان ذلك ممكنًا.

الإجابة رقم 1

يمكنك إما أن يكون لديك فصل منفصل عن التعداد واستخدامه للحصول على الأشياء التي تريدها، أو يمكنك دمج مساحة أسماء في التعداد والحصول على كل شيء في ما يبدو كأنه نفس المكان.

فئة أدوات الوضع

لذلك هذا ليس بالضبط ما تبحث عنه، لكن هذا يسمح لك بتغليف سلوك "الوضع إلى سلسلة" باستخدام طريقة ثابتة.

class ModeUtil {
    public static toString(mode: Mode) {
        return Mode[mode];
    }
}

يمكنك استخدامه هكذا:

const mode = Mode.portrait;
const x = ModeUtil.toString(mode);
console.log(x);

دمج تعداد/مساحة الأسماء للوضع

يمكنك دمج مساحة الاسم مع التعداد لإنشاء ما يبدو كتعداد مع طرق إضافية:

enum Mode {
    X,
    Y
}

namespace Mode {
    export function toString(mode: Mode): string {
        return Mode[mode];
    }

    export function parse(mode: string): Mode {
        return Mode[mode];
    }
}

const mode = Mode.X;

const str = Mode.toString(mode);
alert(str);

const m = Mode.parse(str);
alert(m);

الإجابة رقم 2

يمكنك الحصول على القيمة النصية لتعداد غير ثابت باستخدام الأقواس المربعة:

class Device {
    constructor(public mode:Mode) {
        console.log(Mode[this.mode]);
    }
}

يمكنك أيضًا وضع بعض دوال الأدوات المحددة للـ enum داخل الـ enum، لكن هذا يشبه فقط أعضاء الصفوف الثابتة:

enum Mode {
    landscape,
    portrait
}

namespace Mode {
    export function doSomething(mode:Mode) {
        // your code here
    }
}

الإجابة رقم 3

حوّل enum الخاص بك إلى نمط enum. أجد أن هذه ممارسة أفضل بشكل عام للعديد من اللغات، لأنه بخلاف ذلك ستقيد خيارات التغليف لنوعك. الميل الطبيعي هو switch على قيمة enum، بينما في الواقع يجب أن تذهب أي بيانات أو وظيفة تعتمد على قيمة enum معينة إلى كل نسخة من enum. لقد أضفت بعض الكود الإضافي للتوضيح.

قد لا ينجح هذا إذا كنت تعتمد بشكل خاص على قيم التعداد الأساسية. في تلك الحالة، ستحتاج إلى إضافة عضو للقيم القديمة وتحويل الأماكن التي تحتاجها لاستخدام الخاصية الجديدة.

class Mode {
   public static landscape = new Mode(1920, 1080);
   public static portrait = new Mode(1080, 1920);

   public get Width(): number { return this.mWidth; }
   public get Height(): number { return this.mHeight; }

   // private constructor if possible in a future version of TS
   constructor(
      private mWidth: number,
      private mHeight: number
   ) {
   }

   public GetAspectRatio() {
      return this.mWidth / this.mHeight;
   }
}

الإجابة رقم 4

إضافة إلى محلول فينتون. إذا كنت ترغب في استخدام هذا العدّاد في فصل آخر، تحتاج إلى تصدير كل من التعداد ونطاق الاسم. سيبدو الأمر هكذا:

export enum Mode {
    landscape,
    portrait
}

export namespace Mode {
    export function toString(mode: Mode): string {
        return Mode[mode];
    }
}

ثم تقوم ببساطة باستيراد ملف mode.enum.ts في صفك واستخدامه.