it-swarm.dev

كيفية برمجيا تعداد نوع التعداد؟

لنفترض أن لدي نوع TypeScript enum ، MyEnum ، كما يلي:

enum MyEnum {
    First,
    Second,
    Third
}

ما هي أفضل طريقة في TypeScript 0.9.5 لإنتاج صفيف من قيم enum؟ مثال:

var choices: MyEnum[]; // or Array<MyEnum>
choices = MyEnum.GetValues(); // plans for this?
choices = EnumEx.GetValues(MyEnum); // or, how to roll my own?
76
David Cuccia

هذا هو إخراج جافا سكريبت لهذا التعداد:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["First"] = 0] = "First";
    MyEnum[MyEnum["Second"] = 1] = "Second";
    MyEnum[MyEnum["Third"] = 2] = "Third";
})(MyEnum || (MyEnum = {}));

وهو كائن مثل هذا:

Object {
    0: "First",
    1: "Second",
    2: "Third",
    First: 0,
    Second: 1,
    Third: 2
}

أسماء الأعضاء

للحصول على أسماء أعضاء التعداد ، يمكننا تصفية مفاتيح الكائن عندما تكون القيمة المطابقة رقمًا. القيام بذلك يضمن العثور على أسماء بنفس القيمة:

const names = Object.keys(MyEnum)
    .filter(k => typeof MyEnum[k] === "number") as string[];

يحتوي على: ["First", "Second", "Third"]

قيم الأعضاء

أثناء الحصول على قيم عضو التعداد ، يمكننا تصفية قيم الكائن بأي شيء رقم:

const values = Object.keys(MyEnum)
    .map(k => MyEnum[k])
    .filter(v => typeof v === "number") as number[];

يحتوي على: [0, 1, 2]

فئة التمديد

أعتقد أن أفضل طريقة للقيام بذلك هي إنشاء وظائفك الخاصة (على سبيل المثال ، EnumEx.getNames(MyEnum)). لا يمكنك إضافة وظيفة إلى التعداد.

class EnumEx {
    private constructor() {
    }

    static getNamesAndValues<T extends number>(e: any) {
        return EnumEx.getNames(e).map(n => ({ name: n, value: e[n] as T }));
    }

    static getNames(e: any) {
        return Object.keys(e).filter(k => typeof e[k] === "number") as string[];
    }

    static getValues<T extends number>(e: any) {
        return Object.keys(e)
            .map(k => e[k])
            .filter(v => typeof v === "number") as T[];
    }
}
178
David Sherret

باستخدام TypeScript> = 2.4 يمكنك تحديد تعدادات السلسلة:

enum Color {
  RED = 'Red',
  ORANGE = 'Orange',
  YELLOW = 'Yellow',
  GREEN = 'Green',
  BLUE = 'Blue',
  Indigo = 'Indigo',
  Violet = 'Violet'
}

إخراج جافا سكريبت ES5:

var Color;
(function (Color) {
    Color["RED"] = "Red";
    Color["ORANGE"] = "Orange";
    Color["YELLOW"] = "Yellow";
    Color["GREEN"] = "Green";
    Color["BLUE"] = "Blue";
    Color["Indigo"] = "Indigo";
    Color["Violet"] = "Violet";
})(Color || (Color = {}));

وهو كائن مثل هذا:

const Color = {
  "RED": "Red",
  "ORANGE": "Orange",
  "YELLOW": "Yellow",
  "GREEN": "Green",
  "BLUE": "Blue",
  "Indigo": "Indigo",
  "Violet": "Violet"
}

وبالتالي ، في حالة تعداد السلسلة ، لا توجد حاجة لتصفية الأشياء ، Object.keys(Color) و Object.values(Color) (*) ​​كافية:

const colorKeys = Object.keys(Color);
console.log('colorKeys =', colorKeys);
// ["RED","ORANGE","YELLOW","GREEN","BLUE","Indigo","Violet"]

const colorValues = Object.values(Color);
console.log('colorValues =', colorValues);
// ["Red","Orange","Yellow","Green","Blue","Indigo","Violet"]

colorKeys.map(colorKey => {
  console.log(`color key = ${colorKey}, value = ${Color[colorKey]}`);
});
/*
color key = RED, value = Red
color key = ORANGE, value = Orange
color key = YELLOW, value = Yellow
color key = GREEN, value = Green
color key = BLUE, value = Blue
color key = Indigo, value = Indigo
color key = Violet, value = Violet
*/

شاهد على الإنترنت مثال على ملعب TypeScript

(*) Polyfill اللازمة للمتصفحات القديمة ، راجع https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Object/values#Browser_compatibility

18
tanguy_k

يمكنك إضافة وظائف للحصول على أسماء ومؤشرات التعداد:

enum MyEnum {
  First,
  Second,
  Third
}

namespace MyEnum {
  function isIndex(key):boolean {
    const n = ~~Number(key);
    return String(n) === key && n >= 0;
  }

  const _names:string[] = Object
      .keys(MyEnum)
      .filter(key => !isIndex(key));

  const _indices:number[] = Object
      .keys(MyEnum)
      .filter(key => isIndex(key))
      .map(index => Number(index));

  export function names():string[] {
    return _names;
  }

  export function indices():number[] {
    return _indices;
  }
}

console.log("MyEnum names:", MyEnum.names());
// Prints: MyEnum names: ["First", "Second", "Third"]

console.log("MyEnum indices:", MyEnum.indices());
// Prints: MyEnum indices: [0, 1, 2]

لاحظ أنك يمكن فقط تصدير _names و _indices consts بدلاً من تعريضها من خلال دالة تم تصديرها ، ولكن نظرًا لأن الأعضاء الذين تم تصديرهم أعضاء في التعداد ، فمن الواضح أنه من الواضح أن يكون لهم وظائف حتى لا يتم الخلط بينهما أعضاء التعداد الفعلي.

سيكون من الرائع أن يولد TypeScript شيئًا كهذا تلقائيًا لجميع التعدادات.

8
Rich

لا يوجد مفهوم RTTI (معلومات نوع وقت التشغيل) في TypeScript (اعتقد: انعكاس) ، لذا من أجل القيام بذلك ، يلزم معرفة JavaScript المنقول. لذلك ، بافتراض TypeScript 0.95:

enum MyEnum {
    First, Second, Third
}

يصبح:

var MyEnum;
(function(MyEnum) {
    MyEnum[MyEnum["First"] = 0] = "First";
    MyEnum[MyEnum["Second"] = 1] = "Second";
    MyEnum[MyEnum["Third"] = 2] = "Third";
}

لذلك ، تم تصميم هذا ككائن عادي في javascript ، حيث MyEnum.0 == "First" و MyEnum.First == 0. لذلك ، لتعداد جميع أسماء التعداد ، تحتاج إلى الحصول على جميع الخصائص التي تنتمي إلى الكائن والتي ليست أرقامًا أيضًا:

for (var prop in MyEnum) {         
    if (MyEnum.hasOwnProperty(prop) &&
        (isNaN(parseInt(prop)))) {
        console.log("name: " + prop);
    }
}

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

8
x0n

لقد استخدمت الحل الذي اقترحه David Sherret وكتبت مكتبة npm يمكنك استخدامها المسماة enum-values...

بوابة: تعداد القيم

// Suppose we have an enum
enum SomeEnum {
  VALUE1,
  VALUE2,
  VALUE3
}

// names will be equal to: ['VALUE1', 'VALUE2', 'VALUE3']
var names = EnumValues.getNames(SomeEnum);

// values will be equal to: [0, 1, 2]
var values = EnumValues.getValues(SomeEnum);
4
Slava Shpitalny

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

function listEnum(enumClass) {
    var values = [];
    for (var key in enumClass) {
        values.Push(enum[key]);
    }
    values.length = values.length / 2;
    return values;
}

إنه يعمل لأن TypeScript ستضيف مفاتيح في الخطوة الأولى ، والقيم في الخطوة الثانية.

في TypeScript:

var listEnums = <T> (enumClass: any): T[]=> {
    var values: T[] = [];
    for (var key in enumClass) {
        values.Push(enumClass[key]);
    }
    values.length = values.length / 2;
    return values;
};

var myEnum: TYPE[] = listEnums<TYPE>(TYPE);
2
Chklang

سطر واحد للحصول على قائمة الإدخالات (كائنات/أزواج القيمة الرئيسية):

Object.keys(MyEnum).filter(a=>a.match(/^\D/)).map(name=>({name, value: MyEnum[name] as number}));
2
Venryx
enum MyEnum {
    First, Second, Third, NUM_OF_ENUMS
}

for(int i = 0; i < MyEnum.NUM_OF_ENUMS; ++i) {
    // do whatever you need to do.
}
2
joe

إجابة جو جعلني أدرك أنه من الأسهل بكثير الاعتماد على أول مفاتيح رقمية من إجراء اختبارات أكثر تعقيدًا:

function getEnumMembers(myEnum): string[]
{
    let members = []
    for(let i:number = 0; true; i++) {
        if(myEnum[i] === undefined) break
        members.Push(myEnum[i])
    }

    return members
}

enum Colors {
    Red, Green, Blue
}

console.log(getEnumMembers(myEnum))
1
kbtzr