TypeScript enum ไปยัง object array


100

ฉันมี enum กำหนดด้วยวิธีนี้:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

อย่างไรก็ตามฉันต้องการให้แสดงเป็นอาร์เรย์วัตถุ / รายการจาก API ของเราดังนี้:

[{id: 1, name: 'Percentage'}, 
 {id: 2, name: 'Numeric Target'},
 {id: 3, name: 'Completed Tasks'},
 {id: 4, name: 'Average Milestone Progress'},
 {id: 5, name: 'Not Measured'}]

มีวิธีที่ง่ายและเป็นธรรมชาติในการทำเช่นนี้หรือฉันต้องสร้างฟังก์ชันที่หล่อ enum ให้เป็นทั้ง int และสตริงและสร้างวัตถุลงในอาร์เรย์หรือไม่?


Enums เป็นวัตถุจริงที่มีอยู่ในรันไทม์ คุณจึงสามารถย้อนกลับการแม็ปได้โดยทำสิ่งนี้: GoalProgressMeasurements[GoalProgressMeasurements.Completed_Tasks]เพื่อรับชื่อ enum ฉันไม่รู้ว่าจะช่วยได้ไหม
Diullei

คุณสามารถให้คำอธิบายที่ดีกว่าสำหรับ "จาก API ของเรา" ได้ไหมอาจจะยกตัวอย่างการใช้งาน
gilamran

คำตอบ:


47

บิตที่ยุ่งยากคือ TypeScript จะแมป enum ในอ็อบเจ็กต์ที่ปล่อยออกมาเป็นสองเท่าดังนั้นจึงสามารถเข้าถึงได้ทั้งด้วยคีย์และค่า

enum MyEnum {
    Part1 = 0,
    Part2 = 1
}

จะแสดงเป็น

{
   Part1: 0,
   Part2: 1,
   0: 'Part1',
   1: 'Part2'
}

ดังนั้นคุณควรกรองวัตถุก่อนการแมป ทางออกของ @Diullei จึงมีคำตอบที่ถูกต้อง นี่คือการใช้งานของฉัน:

// Helper
const StringIsNumber = value => isNaN(Number(value)) === false;

// Turn enum into array
function ToArray(enumme) {
    return Object.keys(enumme)
        .filter(StringIsNumber)
        .map(key => enumme[key]);
}

ใช้แบบนี้:

export enum GoalProgressMeasurements {
    Percentage,
    Numeric_Target,
    Completed_Tasks,
    Average_Milestone_Progress,
    Not_Measured
}

console.log(ToArray(GoalProgressMeasurements));

1
mmm ถ้าenum MyEnum { Part1 = 0, Part2 = 1 }เปลี่ยนเป็น { Part1: 0, Part2: 1, 0: 'Part1', 1: 'Part2' } แล้วทำไมเมื่อคุณconsole.log(Object.values(MyEnum))พิมพ์แค่ 0,1?
Juan JoséRamírez

@ JuanJoséRamírezคุณเห็นที่ไหน สำหรับฉันObject.values(MyEnum)ประเมินเป็น["Part1", "Part2", 0, 1]
user8363

ฉันเพิ่งพิมพ์console.log(Object.values(MyEnum))ในส่วนประกอบของฉัน ฉันใช้เชิงมุมไม่แน่ใจว่าเกี่ยวข้องกันหรือไม่ ฉันไม่ค่อยมีประสบการณ์ใน TypeScript
Juan JoséRamírez

พฤติกรรมอาจเปลี่ยนไปใน TS เวอร์ชันต่างๆได้หรือไม่
Juan JoséRamírez

3
ฉันได้ตรวจสอบประเภทเอกสารcriptlang.org/docs/handbook/release-notes/…และดูเหมือนว่าสตริง enums จะมีพฤติกรรมที่แตกต่างออกไป พวกเขาไม่ได้รับการทำแผนที่ย้อนกลับที่สร้างขึ้นเลย ในโค้ดของฉันฉันใช้สตริง enum ไม่ใช่สตริงในตัวอย่างนี้
Juan JoséRamírez

39

หากคุณใช้ ES6

มันจะทำให้คุณอาร์เรย์คุณค่าของการได้รับenum

enum Colors {
  WHITE = 0,
  BLACK = 1,
  BLUE = 3
}

const colorValueArray = Object.values(Colors); //[ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]

คุณจะได้รับเช่นนี้colorValueArray [ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]คีย์ทั้งหมดจะอยู่ในครึ่งแรกของอาร์เรย์และค่าทั้งหมดในครึ่งหลัง


8
โปรดทราบว่าสิ่งนี้จะทำให้เกิดรายการซ้ำ ค่าสตริงและค่าตัวเลขสำหรับแต่ละองค์ประกอบซึ่งเป็นประเภท(string | YourEnumType)[]ที่ไม่ใช่สิ่งที่คุณอาจต้องการในแต่ละกรณี
Christian Ivicevic

จะรับประกันได้หรือไม่ว่าครึ่งปีแรกจะเป็นกุญแจสำคัญและครึ่งหลังจะเป็นค่านิยม? อ้างอิงใด ๆ
Neekey

36

Enums เป็นวัตถุจริงที่มีอยู่ในรันไทม์ ดังนั้นคุณสามารถย้อนกลับการแมปได้โดยทำสิ่งนี้:

let value = GoalProgressMeasurements.Not_Measured;
console.log(GoalProgressMeasurements[value]);
// => Not_Measured

ตามที่คุณสามารถใช้รหัสต่อไปนี้:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

let map: {id: number; name: string}[] = [];

for(var n in GoalProgressMeasurements) {
    if (typeof GoalProgressMeasurements[n] === 'number') {
        map.push({id: <any>GoalProgressMeasurements[n], name: n});
    }
}

console.log(map);

อ้างอิง: https://www.typescriptlang.org/docs/handbook/enums.html


3
คุณไม่จำเป็นต้องเขียนค่าเริ่มต้น= 2จนกว่า= 5- สิ่งที่ตามมา= 1คือ +1 โดยอัตโนมัติ
sebilasse

8
บางทีคุณอาจไม่จำเป็นต้องทำ แต่เป็นการแสดงออกมากกว่า ซึ่งทำให้ IMHO ดีขึ้น
SubliemeSiem

4
เพียงแค่หมายเหตุนี้ใช้ไม่ได้กับ enums ค่าสตริง
Bashar Ali Labadi

21

โซลูชันที่ง่าย คุณสามารถใช้ฟังก์ชันต่อไปนี้เพื่อแปลง Enum ของคุณเป็นอาร์เรย์ของวัตถุ

 buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
 }

หากคุณต้องการตัดขีดล่างออกเราสามารถใช้ regex ได้ดังนี้:

buildGoalProgressMeasurementsArray(): Object[] {

    return Object.keys(GoalProgressMeasurements)
              .map(key => ({ id: GoalProgressMeasurements[key], name: key.replace(/_/g, ' ') }))
 }

7
คุณควรกรองคีย์ของประเภทหมายเลข Object.keys(GoalProgressMeasurements) .filter(key => typeof GoalProgressMeasurements[key] === 'number') .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
Salvador Rubio Martinez

12

ฉันใช้

Object.entries(GoalProgressMeasurement).filter(e => !isNaN(e[0]as any)).map(e => ({ name: e[1], id: e[0] }));

1 บรรทัดง่ายๆที่ได้ผล

มันจะทำงานใน 3 ขั้นตอนง่ายๆ
- Object.entriesโหลดรวมกันของคีย์และค่าใช้
- กรองตัวเลขที่ไม่ใช่ (เนื่องจาก typescript สร้างค่าสำหรับการค้นหาแบบย้อนกลับ)
- จากนั้นเราจับคู่กับวัตถุอาร์เรย์ที่เราชอบ


ไม่สามารถใช้งานร่วมกับ IE ที่มี front-end ได้ (ไม่ควรรองรับ ie เป็นคำตอบที่ดี ... แต่ฉันเดาว่าลูกค้า) หวังว่าบาเบลจะปรากฏขึ้น แต่ยึดติดกับแนวทางอื่นเนื่องจากฉันยังไม่ได้ตรวจสอบ
TamusJRoyce

9
class EnumHelpers {

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

    static getNames(e: any) {
        return EnumHelpers.getObjValues(e).filter(v => typeof v === 'string') as string[];
    }

    static getValues<T extends number>(e: any) {
        return EnumHelpers.getObjValues(e).filter(v => typeof v === 'number') as T[];
    }

    static getSelectList<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
        const selectList = new Map<T, string>();
        this.getValues(e).forEach(val => selectList.set(val as T, stringConverter(val as unknown as U)));
        return selectList;
    }

    static getSelectListAsArray<T extends number, U>(e: any, stringConverter: (arg: U) => string) {
        return Array.from(this.getSelectList(e, stringConverter), value => ({ value: value[0] as T, presentation: value[1] }));
    }

    private static getObjValues(e: any): (number | string)[] {
        return Object.keys(e).map(k => e[k]);
    }
}

1
ขอบคุณสำหรับตัวช่วยเหล่านี้ มีประโยชน์มาก.
user906573

8

สิ่งนี้จะทำให้คุณมีอาร์เรย์ของค่า enum:

 Object.values(myEnum);

เหตุใดจึงไม่ใช่คำตอบอันดับต้น ๆ ยังไงก็ขอบคุณ!
Paulo Queiroz

@PauloQueiroz จะขึ้นอันดับสูงสุดโดยอัตโนมัติหากการโหวตเพิ่มขึ้น ขอบคุณ!
Gaurav Panwar

เนื่องจากไม่ได้ให้ผลลัพธ์ที่ถูกต้องตรวจสอบstackoverflow.com/a/57266281/3548345
walox

4

อันดับแรกเราได้รับคีย์อาร์เรย์สำหรับ enum นี้ จากนั้นใช้ฟังก์ชัน map () เราจะแปลงข้อมูลให้อยู่ในรูปแบบที่ต้องการ id ได้มาจากคีย์ชื่อได้มาจาก enum ด้วยคีย์เดียวกัน

const converted = Object.keys(GoalProgressMeasurements).map(key => {
        return {
            id: GoalProgressMeasurements[key],
            name: key,
        };
    });

2
ยินดีต้อนรับสู่ stackoverflow เมื่อตอบคำถามคุณควรอธิบายว่าข้อมูลโค้ดของคุณทำอะไรได้บ้าง สำหรับข้อมูลเพิ่มเติมโปรดดูที่นี่: How to Answer
Djensen


โปรดพิจารณาเพิ่มคำอธิบายหรือรายละเอียดในคำตอบของคุณ แม้ว่าอาจจะตอบคำถามได้เพียงแค่เพิ่มโค้ดเป็นคำตอบ แต่ไม่ได้บอกว่าช่วยให้ OP หรือสมาชิกในชุมชนในอนาคตเข้าใจปัญหาหรือแนวทางแก้ไขที่เสนอ
Maxim

2

ฉันไม่ชอบคำตอบใด ๆ ข้างต้นเพราะไม่มีคำตอบใดที่จัดการส่วนผสมของสตริง / ตัวเลขที่สามารถเป็นค่าใน TypeScript enums ได้อย่างถูกต้อง

ฟังก์ชันต่อไปนี้เป็นไปตามความหมายของ TypeScript enums เพื่อให้แผนที่ของคีย์ที่เหมาะสมกับค่า จากนั้นการรับอาร์เรย์ของวัตถุหรือเพียงแค่คีย์หรือเพียงค่าเป็นเรื่องเล็กน้อย

/**
 * Converts the given enum to a map of the keys to the values.
 * @param enumeration The enum to convert to a map.
 */
function enumToMap(enumeration: any): Map<string, string | number> {
  const map = new Map<string, string | number>();
  for (let key in enumeration) {
      //TypeScript does not allow enum keys to be numeric
      if (!isNaN(Number(key))) continue;

      const val = enumeration[key] as string | number;

      //TypeScript does not allow enum value to be null or undefined
      if (val !== undefined && val !== null)
          map.set(key, val);
  }

  return map;
}

ตัวอย่างการใช้งาน:

enum Dog {
    Rover = 1,
    Lassie = "Collie",
    Fido = 3,
    Cody = "Mutt",
}

let map = enumToMap(Dog); //Map of keys to values

lets objs = Array.from(map.entries()).map(m => ({id: m[1], name: m[0]})); //Objects as asked for in OP
let entries = Array.from(map.entries()); //Array of each entry
let keys = Array.from(map.keys()); //An array of keys
let values = Array.from(map.values()); //An array of values

ฉันจะชี้ให้เห็นด้วยว่า OP กำลังคิดถึง enums ไปข้างหลัง "คีย์" ใน enum อยู่ทางด้านซ้ายมือในทางเทคนิคและค่าจะอยู่ทางด้านขวามือ TypeScript ช่วยให้คุณสามารถทำซ้ำค่าใน RHS ได้มากเท่าที่คุณต้องการ


1

enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}
    
const array = []
    
for (const [key, value] of Object.entries(GoalProgressMeasurements)) {
    if (!Number.isNaN(Number(key))) {
        continue;
    }

    array.push({ id: value, name: key.replace('_', '') });
}

console.log(array);


โปรดใส่คำตอบของคุณในบริบทเสมอแทนที่จะวางโค้ด ดูที่นี่สำหรับรายละเอียดเพิ่มเติม
gehbiszumeis

0

คุณสามารถทำได้ด้วยวิธีนี้:

export enum GoalProgressMeasurements {
    Percentage = 1,
    Numeric_Target = 2,
    Completed_Tasks = 3,
    Average_Milestone_Progress = 4,
    Not_Measured = 5
}

export class GoalProgressMeasurement {
    constructor(public goalProgressMeasurement: GoalProgressMeasurements, public name: string) {
    }
}

export var goalProgressMeasurements: { [key: number]: GoalProgressMeasurement } = {
    1: new GoalProgressMeasurement(GoalProgressMeasurements.Percentage, "Percentage"),
    2: new GoalProgressMeasurement(GoalProgressMeasurements.Numeric_Target, "Numeric Target"),
    3: new GoalProgressMeasurement(GoalProgressMeasurements.Completed_Tasks, "Completed Tasks"),
    4: new GoalProgressMeasurement(GoalProgressMeasurements.Average_Milestone_Progress, "Average Milestone Progress"),
    5: new GoalProgressMeasurement(GoalProgressMeasurements.Not_Measured, "Not Measured"),
}

และคุณสามารถใช้งานได้ดังนี้:

var gpm: GoalProgressMeasurement = goalProgressMeasurements[GoalProgressMeasurements.Percentage];
var gpmName: string = gpm.name;

var myProgressId: number = 1; // the value can come out of drop down selected value or from back-end , so you can imagine the way of using
var gpm2: GoalProgressMeasurement = goalProgressMeasurements[myProgressId];
var gpmName: string = gpm.name;

คุณสามารถขยาย GoalProgressMeasurement ด้วยคุณสมบัติเพิ่มเติมของวัตถุได้ตามที่คุณต้องการ ฉันใช้แนวทางนี้สำหรับการแจงนับทุกครั้งที่ควรเป็นวัตถุที่มีค่ามากกว่า


0

เนื่องจาก enums ที่มีค่า Strings แตกต่างจากค่าที่มีค่าตัวเลขจึงเป็นการดีกว่าที่จะกรอง nonNumbers จากโซลูชัน @ user8363

นี่คือวิธีที่คุณจะได้รับค่าจาก enum ทั้งสตริงจำนวนคละ:

    //Helper
    export const StringIsNotNumber = value => isNaN(Number(value)) === true;
    
    // Turn enum into array
    export function enumToArray(enumme) {
      return Object.keys(enumme)
       .filter(StringIsNotNumber)
       .map(key => enumme[key]);
    }


0

ฉันประหลาดใจในเธรด TypeScript ที่ไม่มีใครให้ฟังก์ชัน TypeScript ที่ถูกต้องโดยรองรับการพิมพ์ นี่คือรูปแบบของโซลูชัน @ user8363:

const isStringNumber = (value: string) => isNaN(Number(value)) === false;

function enumToArray<T extends {}>(givenEnum: T) {
  return (Object.keys(givenEnum).filter(isStringNumber) as (keyof T)[]).map(
    (key) => givenEnum[key]
  );
}

-1

มีวิธีง่ายๆดังนั้นเมื่อคุณเรียกใช้Object.keys(Enum)สิ่งนั้นจะให้อาร์เรย์ของค่าและคีย์แก่คุณในค่าสไลซ์แรกและในคีย์ที่สองดังนั้นทำไมเราไม่เพียงส่งคืนส่วนที่สองโค้ดด้านล่างนี้ใช้ได้กับฉัน .

enum Enum {
   ONE,
   TWO,
   THREE,
   FOUR,
   FIVE,
   SIX,
   SEVEN
}
const keys = Object.keys(Enum); 
console.log(keys.slice(keys.length / 2));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.