TypeScript - كيف تحصل على أسماء عناصر التعداد؟


أود تكرار كائن تعداد TypeScript والحصول على اسم كل رمز معدد، على سبيل المثال: enum myEnum { entry1, entry2 }

for (var entry in myEnum) { 
    // use entry's name here, e.g., "entry1"
}

الإجابة رقم 1

على الرغم من أن الإجابة مُقدَّمة بالفعل، إلا أن قلّة قليلة أشارت إلى المستندات

إليك مقتطف

enum SampleEnum {
    A,
     
}
let nameOfA = SampleEnum[SampleEnum.A]; // "A"

ضع في اعتبارك أن أعضاء تعداد السلاسل النصية لا يحصلون على خريطة عكسية مُنشأة على الإطلاق.

الإجابة رقم 2

الكود الذي نشرته سيعمل؛ سيطبع جميع أعضاء التعداد، بما في ذلك قيم أعضاء التعداد. على سبيل المثال، الكود التالي:

enum myEnum { bar, foo }

for (var enumMember in myEnum) {
   console.log("enum member: ", enumMember);
}

سيطبع ما يلي:

Enum member: 0
Enum member: 1
Enum member: bar
Enum member: foo

إذا كنت تريد بدلاً من ذلك أسماء الأعضاء فقط، وليس القيم، يمكنك فعل شيء مثل هذا:

for (var enumMember in myEnum) {
   var isValueProperty = Number(enumMember) >= 0
   if (isValueProperty) {
      console.log("enum member: ", myEnum[enumMember]);
   }
}

سيطبع ذلك فقط الأسماء:

Enum member: bar  
Enum member: foo

تنويه: هذا يعتمد قليلاً على تفصيل تنفيذي: يقوم TypeScript بتحويل enums إلى كائن JS مع كون قيم enum أعضاء في الكائن. إذا قرر TS تنفيذه بطريقة مختلفة في المستقبل، فقد تتعطل التقنية المذكورة أعلاه.

الإجابة رقم 3

بالنسبة لي، فإن الطريقة الأسهل والعملية والمباشرة لفهم ما يحدث، هي التعداد التالي:

enum colors { red, green, blue };

سيتم تحويله في الأساس إلى هذا:

var colors = { red: 0, green: 1, blue: 2,
               [0]: "red", [1]: "green", [2]: "blue" }

بسبب هذا، سيكون ما يلي صحيحًا:

colors.red === 0
colors[colors.red] === "red"
colors["red"] === 0

هذا ينشئ طريقة سهلة للحصول على اسم عدد معدَّد كما يلي:

var color: colors = colors.red;
console.log("The color selected is " + colors[color]);

كما أنه يخلق طريقة جيدة لتحويل سلسلة إلى قيمة معددة.

var colorName: string = "green";
var color: colors = colors.red;
if (colorName in colors) color = colors[colorName];

الحالتان أعلاه هما حالتان أكثر شيوعًا، لأنك عادة تكون أكثر اهتمامًا باسم قيمة محددة وتسلسل القيم بطريقة عامة.

الإجابة رقم 4

إذا كنت تبحث فقط عن الأسماء وتكرر لاحقًا استخدم:

Object.keys(myEnum).map(key => myEnum[key]).filter(value => typeof value === 'string') as string[];

الإجابة رقم 5

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

enum Color {
    Red,
    Green,
    Blue,
    "10" // wat
}

var names: string[] = [];
for(var n in Color) {
    if(typeof Color[n] === 'number') names.push(n);
}
console.log(names); // ['Red', 'Green', 'Blue', '10']

الإجابة رقم 6

يبدو أن أيًا من الإجابات هنا لن تعمل مع تعداد السلاسل النصية في وضع strict.

اعتبر التعداد كما يلي:

enum AnimalEnum {
  dog = "dog", cat = "cat", mouse = "mouse"
}

الوصول إلى هذا باستخدام AnimalEnum["dog"] قد يؤدي إلى خطأ مثل:

العنصر له نوع 'any' ضمني لأن التعبير من نوع 'any' لا يمكن استخدامه لفهرسة النوع 'typeof AnimalEnum'.ts(7053).

الحل المناسب لهذه الحالة، اكتبه كالتالي:

AnimalEnum["dog" as keyof typeof AnimalEnum]

الإجابة رقم 7

اعتبارًا من TypeScript 2.4، يمكن أن تحتوي التعدادات على مهيئات نصية https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-4.html

هذا يتيح لك الكتابة:

 enum Order {
      ONE = "First",
      TWO = "Second"
 }

console.log(`One is ${Order.ONE.toString()}`);

واحصل على هذا الإخراج:

واحد هو الأول

الإجابة رقم 8

مع نسخة TypeScript الحالية 1.8.9، أستخدم تعدادًا من النوع المحدد:

export enum Option {
    OPTION1 = <any>'this is option 1',
    OPTION2 = <any>'this is option 2'
}

مع النتائج في هذا الكائن الجافاسكريبت:

Option = {
    "OPTION1": "this is option 1",
    "OPTION2": "this is option 2",
    "this is option 1": "OPTION1",
    "this is option 2": "OPTION2"
}

لذا عليّ الاستعلام من خلال المفاتيح والقيم وإرجاع القيم فقط:

let optionNames: Array<any> = [];    
for (let enumValue in Option) {
    let optionNameLength = optionNames.length;

    if (optionNameLength === 0) {
        this.optionNames.push([enumValue, Option[enumValue]]);
    } else {
        if (this.optionNames[optionNameLength - 1][1] !== enumValue) {
            this.optionNames.push([enumValue, Option[enumValue]]);
        }
    }
}

وأنا أستقبل مفاتيح الخيارات في مصفوفة:

optionNames = [ "OPTION1", "OPTION2" ];

الإجابة رقم 9

هذا الحل يعمل أيضًا.

enum ScreenType {
    Edit = 1,
    New = 2,
    View = 4
}

var type: ScreenType = ScreenType.Edit;

console.log(ScreenType[type]); //Edit

الإجابة رقم 10

إذا كان enums الخاص بك كما يلي:

export enum Colors1 {
  Red = 1,
  Green = 2,
  Blue = 3
}

للحصول على نص وقيمة محددين:

console.log(Colors1.Red); // 1 
console.log(Colors1[Colors1.Red]); // Red

للحصول على قائمة بالقيمة والنص:

public getTextAndValues(e: { [s: number]: string }) {
  for (const enumMember in e) {
    if (parseInt(enumMember, 10) >= 0) {
      console.log(e[enumMember]) // Value, such as 1,2,3
      console.log(parseInt(enumMember, 10)) // Text, such as Red,Green,Blue
    }
  }
}
this.getTextAndValues(Colors1)

إذا كان enums الخاص بك كما يلي:

export enum Colors2 {
  Red = "Red",
  Green = "Green",
  Blue = "Blue"
}

للحصول على نص معين وقيمة:

console.log(Colors2.Red); // Red
console.log(Colors2["Red"]); // Red

للحصول على قائمة بالقيمة والنص:

public getTextAndValues(e: { [s: string]: string }) {
  for (const enumMember in e) {
    console.log(e[enumMember]);// Value, such as Red,Green,Blue
    console.log(enumMember); //  Text, such as Red,Green,Blue
  }
}
this.getTextAndValues(Colors2)

الإجابة رقم 11

حل آخر مثير للاهتمام موجود هنا هو استخدام ES6 Map:

export enum Type {
  low,
  mid,
  high
}

export const TypeLabel = new Map<number, string>([
  [Type.low, 'Low Season'],
  [Type.mid, 'Mid Season'],
  [Type.high, 'High Season']
]);

استخدم

console.log(TypeLabel.get(Type.low)); // Low Season


TypeLabel.forEach((label, value) => {
  console.log(label, value);
});

// Low Season 0
// Mid Season 1
// High Season 2    

الإجابة رقم 12

دع ts-enum-util (github, npm) يقوم بالعمل نيابة عنك ويقدم الكثير من الأدوات الإضافية الآمنة نوعيًا. يعمل مع كلا النوعين من التعدادات، النصية والعددية، مع تجاهل صحيح لمداخل البحث العكسي للمؤشرات العددية للتعدادات العددية:

تعداد السلاسل:

import {$enum} from "ts-enum-util";

enum Option {
    OPTION1 = 'this is option 1',
    OPTION2 = 'this is option 2'
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: ["this is option 1", "this is option 2"]
const values = $enum(Option).getValues();

التعداد الرقمي:

enum Option {
    OPTION1,
    OPTION2
}

// type: ("OPTION1" | "OPTION2")[]
// value: ["OPTION1", "OPTION2"]
const keys= $enum(Option).getKeys();

// type: Option[]
// value: [0, 1]
const values = $enum(Option).getValues();

الإجابة رقم 13

لقد تعبت من النظر في الإجابات الخاطئة، فقمت بذلك بنفسي.

  • هذا يحتوي على اختبارات.
  • يعمل مع جميع أنواع التعدادات.
  • مكتوب بشكل صحيح.
type EnumKeys<Enum> = Exclude<keyof Enum, number>

const enumObject = <Enum extends Record<string, number | string>>(e: Enum) => {
    const copy = {...e} as { [K in EnumKeys<Enum>]: Enum[K] };
    Object.values(e).forEach(value => typeof value === 'number' && delete copy[value]);
    return copy;
};

const enumKeys = <Enum extends Record<string, number | string>>(e: Enum) => {
    return Object.keys(enumObject(e)) as EnumKeys<Enum>[];
};

const enumValues = <Enum extends Record<string, number | string>>(e: Enum) => {
    return [...new Set(Object.values(enumObject(e)))] as Enum[EnumKeys<Enum>][];
};

enum Test1 { A = "C", B = "D"}
enum Test2 { A, B }
enum Test3 { A = 0, B = "C" }
enum Test4 { A = "0", B = "C" }
enum Test5 { undefined = "A" }
enum Test6 { A = "undefined" }
enum Test7 { A, B = "A" }
enum Test8 { A = "A", B = "A" }
enum Test9 { A = "B", B = "A" }

console.log(enumObject(Test1)); // {A: "C", B: "D"}
console.log(enumObject(Test2)); // {A: 0, B: 1}
console.log(enumObject(Test3)); // {A: 0, B: "C"}
console.log(enumObject(Test4)); // {A: "0", B: "C"}
console.log(enumObject(Test5)); // {undefined: "A"}
console.log(enumObject(Test6)); // {A: "undefined"}
console.log(enumObject(Test7)); // {A: 0,B: "A"}
console.log(enumObject(Test8)); // {A: "A", B: "A"}
console.log(enumObject(Test9)); // {A: "B", B: "A"}

console.log(enumKeys(Test1)); // ["A", "B"]
console.log(enumKeys(Test2)); // ["A", "B"]
console.log(enumKeys(Test3)); // ["A", "B"]
console.log(enumKeys(Test4)); // ["A", "B"]
console.log(enumKeys(Test5)); // ["undefined"]
console.log(enumKeys(Test6)); // ["A"]
console.log(enumKeys(Test7)); // ["A", "B"]
console.log(enumKeys(Test8)); // ["A", "B"]
console.log(enumKeys(Test9)); // ["A", "B"]

console.log(enumValues(Test1)); // ["C", "D"]
console.log(enumValues(Test2)); // [0, 1]
console.log(enumValues(Test3)); // [0, "C"]
console.log(enumValues(Test4)); // ["0", "C"]
console.log(enumValues(Test5)); // ["A"] 
console.log(enumValues(Test6)); // ["undefined"] 
console.log(enumValues(Test7)); // [0, "A"]
console.log(enumValues(Test8)); // ["A"]
console.log(enumValues(Test9)); // ["B", "A"]

النسخة الإلكترونية.

الإجابة رقم 14

في TypeScript، يتم تجميع الـ enum إلى خريطة (للحصول على القيمة من المفتاح) في جافاسكريبت:

enum MyEnum {
  entry0,
  entry1,
}

console.log(MyEnum['entry0']); // 0
console.log(MyEnum['entry1']); // 1

كما إنه ينشئ خريطة معكوسة (للحصول على المفتاح من القيمة):

console.log(MyEnum[0]); // 'entry0'
console.log(MyEnum[0]); // 'entry1'

لذلك يمكنك الوصول إلى اسم الإدخال عن طريق القيام بما يلي:

console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'

ومع ذلك، لا يحتوي تعداد السلاسل على خريطة عكسية حسب التصميم (انظر التعليق وطلب السحب) لأن هذا قد يؤدي إلى تعارض بين المفاتيح والقيم في كائن الخريطة.

enum MyEnum {
  entry0 = 'value0',
  entry1 = 'value1',
}

console.log(MyEnum['value0']); // undefined
console.log(MyEnum['value1']); // undefined

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

enum MyEnum {
  entry0 = <any>'value0',
  entry1 = <any>'value1',
}

console.log(MyEnum['value0']); // 'entry0'
console.log(MyEnum['value1']); // 'entry1'
console.log(MyEnum[MyEnum.entry0]); // 'entry0'
console.log(MyEnum[MyEnum.entry1]); // 'entry1'

الإجابة رقم 15

افترض أن لديك enum

export enum SCROLL_LABEL_OFFSET {
  SMALL = 48,
  REGULAR = 60,
  LARGE = 112
}

وتريد إنشاء نوع بناءً على التعداد ولكن ليس مجرد النسخ واللصق. يمكنك استخدام enum لإنشاء type الخاص بك هكذا:

export type ScrollLabelOffset = keyof typeof SCROLL_LABEL_OFFSET;

كنتيجة ستتلقى type بالقيم الممكنة كـ 'SMALL' | 'REGULAR' | 'LARGE'