programing

개체 배열에 대한 TypeScript 열거

nicescript 2023. 3. 14. 23:22
반응형

개체 배열에 대한 TypeScript 열거

다음과 같이 정의된 열거형이 있습니다.

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'}]

이를 위한 쉽고 네이티브한 방법이 있습니까?아니면 int와 문자열 모두에 열거를 캐스팅하고 객체를 배열로 빌드하는 함수를 빌드해야 합니까?

ES8을 사용하는 경우

이 경우만 완벽하게 작동합니다.지정된 열거형의 값 배열이 제공됩니다.

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 ]모든 키는 어레이의 전반부에 있고 모든 값은 후반부에 있습니다.

이런 열거형도 잘 될 거야

enum Operation {
    READ,
    WRITE,
    EXECUTE
}

그러나 이 솔루션은 이와 같은 이기종 Enum에서는 작동하지 않습니다.

enum BooleanLikeHeterogeneousEnum {
  No = 0,
  Yes = "YES",
}

까다로운 비트는 TypeScript가 내보낸 객체의 열거형을 '더블' 매핑하므로 키와 값으로 모두 액세스할 수 있습니다.

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));

Enum은 런타임에 존재하는 실제 개체입니다.따라서 다음과 같은 방법으로 매핑을 되돌릴 수 있습니다.

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

단순히 열거값 배열을 반환합니다.

 Object.values(myEnum);

간단한 솔루션다음 함수를 사용하여 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, ' ') }))
 }

사용하고 있다

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

작업을 수행하는 단순한 1줄입니다.

로 할 수 .
을 - 키와 값의 조합으로 Object.entries
타이프스크립트라고 합니다.
배열 을 합니다 -그러다

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]);
    }
}

polkovnikov.ph 덕분에 대부분의 사용 사례에 적합한 솔루션을 찾을 수 있었습니다.

질문에 대한 유효한 해결책

type Descripted<T> = {
    [K in keyof T]: {
        readonly id: T[K];
        readonly description: string;
    }
}[keyof T]

/**
 * Helper to produce an array of enum descriptors.
 * @param enumeration Enumeration object.
 * @param separatorRegex Regex that would catch the separator in your enum key.
 */
export function enumToDescriptedArray<T>(enumeration: T, separatorRegex: RegExp = /_/g): Descripted<T>[] {
    return (Object.keys(enumeration) as Array<keyof T>)
        .filter(key => isNaN(Number(key)))
        .filter(key => typeof enumeration[key] === "number" || typeof enumeration[key] === "string")
        .map(key => ({
            id: enumeration[key],
            description: String(key).replace(separatorRegex, ' '),
        }));
}

예:


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

console.log(enumToDescriptedArray(GoalProgressMeasurements))
// Produces:
/*
[
    {id: 1, description: "Percentage"},
    {id: 2, description: "Numeric Target"},
    {id: 3, description: "Completed Tasks"},
    {id: 4, description: "Average Milestone Progress"},
    {id: 5, description: "Not Measured"}
]
*/

또한 열거형 객체를 가지고 있는 사용 가능한 값의 배열에 매핑하기 위해 사용하는 유용한 util 함수도 있습니다.

더 매퍼

type NonFunctional<T> = T extends Function ? never : T;

/**
 * Helper to produce an array of enum values.
 * @param enumeration Enumeration object.
 */
export function enumToArray<T>(enumeration: T): NonFunctional<T[keyof T]>[] {
    return Object.keys(enumeration)
        .filter(key => isNaN(Number(key)))
        .map(key => enumeration[key])
        .filter(val => typeof val === "number" || typeof val === "string");
}

업무용 유스케이스

  • 숫자 열거
enum Colors1 {
    WHITE = 0,
    BLACK = 1
}
console.log(Object.values(Colors1)); // ['WHITE', 'BLACK', 0, 1]
console.log(enumToArray(Colors1));   // [0, 1]
  • 문자열 열거
enum Colors2 {
    WHITE = "white",
    BLACK = "black"
}
console.log(Object.values(Colors2)); // ['white', 'black']
console.log(enumToArray(Colors2));   // ['white', 'black']
  • 이종 열거
enum Colors4 {
    WHITE = "white",
    BLACK = 0
}
console.log(Object.values(Colors4)); // ["BLACK", "white", 0]
console.log(enumToArray(Colors4));   // ["white", 0]
  • Enum이 내보낸 함수가 있는 네임스페이스와 병합됨

enum Colors3 {
    WHITE = "white",
    BLACK = "black"
}
namespace Colors3 {
    export function fun() {}
}
console.log(Object.values(Colors3)); // ['white', 'black', Function]
console.log(enumToArray(Colors3));   // ['white', 'black']

TypeScript enum에서 값이 될 수 있는 문자열/숫자의 조합을 올바르게 처리하는 답변이 없기 때문에 위의 답변 중 어느 것도 마음에 들지 않았습니다.

다음 함수는 TypeScript enums의 의미론에 따라 키에 대한 적절한 Map to value를 제공합니다.여기서 객체 배열, 키 또는 값만 가져오는 것은 매우 간단합니다.

/**
 * 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

let 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가 에넘을 거꾸로 생각하고 있다는 것도 지적하겠습니다.열거형의 "키"는 엄밀히 말하면 왼쪽에 있고 값은 오른쪽에 있습니다.TypeScript를 사용하면 원하는 만큼 RHS 값을 반복할 수 있습니다.

한 줄만:

Object.entries(GoalProgressMeasurements).map(([key, value]) => ({id: key, value: value}))

어레이 내부의 열거값을 가져오는 예:

export enum DocumentationTypeEnum {
  GDPR = 'GDPR',
  HELP = 'HELP',
  OTHER = 'OTHER',
  FOOTER = 'FOOTER'
}
const keys = Object.keys(DocumentationTypeEnum);
    
console.log(keys); // Output :  ["GDPR", "HELP", "OTHER", "FOOTER"]

먼저 이 열거형의 키 배열을 가져옵니다.그런 다음 지도() 기능을 사용하여 데이터를 원하는 형식으로 변환합니다.id는 키에서 취득하고, name은 같은 키로 enum에서 취득합니다.

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

ES8 Object.entries를 사용한 또 다른 접근법

export enum Weeks {  
    MONDAY = 1,  
    TUESDAY= 2,  
    WEDNESDAY = 3,  
    THURSDAY = 4,  
    FRIDAY = 5,  
    SATURDAY=6,  
    SUNDAY=7,  
}


function convertEnumToArray(){
   const arrayObjects = []            
     // Retrieve key and values using Object.entries() method. 
     for (const [propertyKey, propertyValue] of Object.entries(Weeks)) { 

      // Ignore keys that are not numbers
      if (!Number.isNaN(Number(propertyKey))) {  
        continue;  
      }  

      // Add keys and values to array
      arrayObjects.push({ id: propertyValue, name: propertyKey });  
    }        

  console.log(arrayObjects); 
}

다음을 생성합니다.

[ 
  { id: 1, name: 'MONDAY' },  
  { id: 2, name: 'TUESDAY' },  
  { id: 3, name: 'WEDNESDAY' },  
  { id: 4, name: 'THURSDAY' },  
  { id: 5, name: 'FRIDAY' },  
  { id: 6, name: 'SATURDAY' },  
  { id: 7, name: 'SUNDAY' } 
] 

블로그에서 뻔뻔하게 도둑맞았다

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);

간단한 해결책이 있습니다. 그래서 당신이 도망칠 때Object.keys(Enum)첫 번째 슬라이스 값 및 두 번째 슬라이스 키에서 값 배열과 키를 얻을 수 있으므로 두 번째 슬라이스만 반환하지 않는 이유는 아래 코드가 좋습니다.

enum Enum {
   ONE,
   TWO,
   THREE,
   FOUR,
   FIVE,
   SIX,
   SEVEN
}
const keys = Object.keys(Enum); 
console.log(keys.slice(keys.length / 2));

저는 몇 달 만에 활자본을 알았고, 아래의 솔루션이 효과가 있었습니다.누군가에게 도움이 되길 바랍니다.

export enum ScheduleType {
  Basic = <any>'B',
  Consolidated = <any>'C',
}

scheduleTypes = Object.keys(ScheduleType)
.filter((k, i) => i % 2)
.map((key: any) => {
  return {
    systemValue: key,
    displayValue: ScheduleType[key],
  };
});

다음 결과를 얻었습니다. [{displayValue: "Basic", systemValue: "B", {displayValue: "Consolidated", systemValue: "C"}]

열거형 엔트리의 리스트가 필요한 경우 TS Enums를 사용하지 않도록 하겠습니다.

실행 시 Enum은 개체로 구현되지만 다음 경우에만 예상대로 작동합니다.

enum X {
  Z = 'z',
  F = 'f'
};

console.log(Object.values(X))
console.log(Object.keys(X))
>>>
[LOG]: ["z", "f"] 
[LOG]: ["Z", "F"] 

이 경우 트랩과 함께 동작합니다(TS를 통해 수치로 값에 액세스할 수 있습니다).

enum X {
  Z,
  F
};

console.log(Object.values(X))
console.log(Object.keys(X))
>>>
[LOG]: ["Z", "F", 0, 1] 
[LOG]: ["0", "1", "Z", "F"] 

따라서 Enum을 루프하기 위해 쓰는 함수는 Enum 정의에 따라 작동/실패합니다.그게 뭐냐면...좋지 않습니다.

결론:Enum은 개체로 사용하도록 설계되지 않았습니다.사용하다const대신enum키 및 값 수집에 액세스해야 하는 경우:

const Enumed = {
    X: 1,
    Y: 2
}

Typescript는 오브젝트 키의 존재를 제어하며 사용자는 다음을 수행할 수 있습니다.Object.keys, 등, 안전하고 일관성 있는 방법으로.

export function enumKeys(E: any): string[] {
    return Object.keys(E).filter(k => isNaN(Number(k)));
}

export function enumValues(E: any): string[] | number[] {
    return enumKeys(E).map(k => E[k as any]);
}

양쪽에서 동작:

enum TestA {
    RED = "red",
    BLUE = "blue"
}

enum TestB {
    ONE = 1,
    TWO = 2
}
function enumKeys(_enum) {
  const entries = Object.entries(_enum).filter(e => !isNaN(Number(e[0])));
  if (!entries.length) {
    // enum has string values so we can use Object.keys
    return Object.keys(_enum);
  }
  return entries.map(e => e[1]);
}

다음과 같이 할 수 있습니다.

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를 확장할 수 있습니다.값을 더 많이 포함하는 개체여야 하는 모든 열거에 대해 이 방법을 사용합니다.

Strings 값을 가진 Enum과 숫자 값을 가진 Enum은 다르므로 @user8363 솔루션에서 nonNumbers를 필터링하는 것이 좋습니다.

다음은 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]);
    }

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]
  );
}

될 것도 않고, 그렇지 것 .그렇지 않으면, 그 주문의 후반을 잘라내는 것은 충분히 쉬울 것입니다.Object.entries결과 및 맵이 표시됩니다.

위의 답변에 관한 유일한 (매우 사소한) 문제는 다음과 같은 문제가 있습니다.

  • 문자열과 숫자 사이에 불필요한 변환이 많이 있습니다.
  • 단일 반복이 깨끗하고 효과적일 때 엔트리가 2회 반복됩니다.
type StandardEnum = { [id: string]: number | string; [nu: number]: string;}

function enumToList<T extends StandardEnum> (enm: T) : { id: number; description: string }[] {
    return Object.entries(enm).reduce((accum, kv) => {
        if (typeof kv[1] === 'number') {
            accum.push({ id: kv[1], description: kv[0] })
        }
        return accum
    }, []) // if enum is huge, perhaps pre-allocate with new Array(entries.length / 2), however then push won't work, so tracking an index would also be required
}

탐:

쇼트(<10 요소) 열거형에서만 동작합니다.

const keys = Object.keys(Enum).filter((el: string) => el.length > 1)
console.log(keys)
  1. Object.keys()는 ['0', '1', '2', 'enumElement1', 'enumElement2', enumElement3]의 배열을 반환합니다.
  2. filter()는 모든 요소를 가져와서 (문자열 때문에) 길이를 체크하고 결과 배열에서 모든 숫자를 제외합니다.

문에 기반한 이 메서드: enum 키는 숫자일 수 없습니다.

export const isNumeric = (num?: Value | null): num is number => {
  if (num === undefined || num === null) {
    return false;
  } 
  
  const number = +num;

  if (number - number !== 0) {
    // Discard Infinity and NaN
    return false;
  }

  if (number === num) {
    return true;
  }

  if (typeof num === 'string') {
    return !(number === 0 && num.trim() === '');
  }
  return false;
};

enum En  {
  ewq1 = 1,
  we2 = 'ss',
  sad = 'sad',
}

type TEnum = {
    [id: string]: number | string;
}

export const getEnumValues = <T extends TEnum>(enumerable: T) =>
  Object.keys(enumerable)
    .filter((x) => !isNumeric(x))
    .map((key) => enumerable[key] as T[keyof T]) 

console.log(getEnumValues(En)) // [1, "ss", "sad"] 

또 다른 방법은

export const GoalNames = {
    [GoalProgressMeasurements.Percentage] = 'Percentage',
    [GoalProgressMeasurements.Numeric_Target] = 'Numeric Target',
    [GoalProgressMeasurements.Completed_Tasks] = 'Completed Tasks',
    [GoalProgressMeasurements.Average_Milestone_Progress] = 'Average Milestone Progress',
    [GoalProgressMeasurements.Not_Measured] = 'Not Measured'
}

문의처:

const name = GoalNames[goalEnumVal];

나는 이 방법으로 해결했다.

        const listKeys = Object.keys(TripStatus); //TripStatus is enum type
        const numOfItem = listKeys.length/2;
        for(let i=0; i<numOfItem; i++){
          this.listStatus.push({
            id: listKeys[i],
            name: listKeys[numOfItem+i]
          })
        }

enum 변수는 다음과 같습니다.

 enum EnumName {
      A = 1,
      B = 2
    };

다음으로 리스트는 다음과 같습니다.

const list = Object.keys(Enum)
.filter((value => isNaN(Number(value)) === false))
      .map(key => ({ id: key, value: Enum[key] }));

목록의 값은 다음과 같습니다.

list = [ 
{ id:1 , value: A },
{ id:2 , value: B },
];
 this worked for me :

    export enum FeedBackType {
    FEEDBACK1= 'FEEDBACK1',
    FEEDBACK2= 'FEEDBACK2',
    FEEDBACK3= 'FEEDBACK3',
    }

----------------------------------------------------------------- 
    export function getTypeFeedBackList() {
    let feedbackList: FeedBackType[] = [];
    Object.keys(FeedBackType).map((key) => {
    let strEnum = key as unknown as FeedBackType;
    feedbackList.push(strEnum);
    });
    return feedbackList;
    }
---------------------------------------------------------------- 
declare this :

    public feedbackList: FeedBackType[] = [];

and after call your function in  :

    ngOnInit(): void {
    this.feedbackList = getTypeFeedBackList();
    console.log(this.feedbackList); 
    }

Happy coding ;) 

이런 식으로 해결했어요다음과 같은 열거형이 있다고 가정합니다.

export enum UnitEnum {
  GRAM = 'gm',
  KILOGRAM = 'kg',
  LITRE = 'lt',
  CENTIMETER = 'cm',
  INCH = 'in',
  METER = 'mt',
  KILOMETER = 'km',
}

그리고 이런 수업도 있고

export interface Unit {
  Name: string;
  Symbol: string;
}

그런 다음 다음과 같은 함수를 만들어 특정 유형의 객체에 이기종 Enum을 매핑할 수 있습니다.

export function getDefaultUnits() {
  const myUnits = Object.entries(UnitEnum).map(x => {
    return { Name: x[0], Symbol: x[1] } as Unit
  })

  console.log(myUnits);

  return myUnits;
}

언급URL : https://stackoverflow.com/questions/43100718/typescript-enum-to-object-array

반응형