객체 배열에 대한 TypeScript 열거 형


110

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

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와 문자열로 캐스팅하고 개체를 배열로 빌드하는 함수를 빌드해야합니까?


열거 형은 런타임에 존재하는 실제 개체입니다. 따라서 다음과 같이 매핑을 반전 할 수 GoalProgressMeasurements[GoalProgressMeasurements.Completed_Tasks]있습니다. 열거 형 이름을 가져옵니다. 도움이되는지 모르겠습니다.
Diullei

"우리의 API에서"아마도 사용의 예를 얻었다 당신은 더 나은 설명을 제공 할 수
gilamran

답변:


52

까다로운 부분은 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));

1
음 경우 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))구성 요소를 인쇄 했습니다. 나는 각도를 사용하고 있는데 그것이 관련되어 있는지 확실하지 않습니다. 나는 타이프에 경험이 아니에요
후안 호세 라미레즈에게

다른 TS 버전을 통해 동작이 변경 될 수 있습니까?
Juan José Ramírez

3
나는 docs typescriptlang.org/docs/handbook/release-notes/…를 확인했는데 문자열 열거 형이 다른 동작을하는 것 같습니다. 역 매핑이 전혀 생성되지 않습니다. 내 코드에서는이 예제의 문자열이 아닌 문자열 열거 형을 사용했습니다.
Juan José Ramírez

46

ES8을 사용하는 경우

이 경우에만 완벽하게 작동합니다. 주어진 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 ]입니다. 모든 키는 배열의 전반부에 있고 모든 값은 후반부에 있습니다.

이런 종류의 열거 형도 잘 작동합니다.

enum Operation {
    READ,
    WRITE,
    EXECUTE
}

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

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

9
이렇게하면 중복이 생성됩니다. 각 요소의 문자열 값과 숫자 값, 즉 (string | YourEnumType)[]각 경우에 원하는 것이 아닌 유형 입니다.
Christian Ivicevic

전반부가 키이고 후반부가 값이 될 것이라는 것이 보장됩니까? 어떤 참조?
Neekey

1
Object.values()ES6의 일부가 아닙니다. ES2017의 일부입니다.
atiyar

ES8과 같은 것은 없습니다. @atiyar가 말했듯이 ES2017이라고합니다.
Heretic Monkey

37

열거 형은 런타임에 존재하는 실제 개체입니다. 따라서 다음과 같이 매핑을 되돌릴 수 있습니다.

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
-이후의 모든 항목 은 자동으로 +1이 = 2될 때까지 기본값을 쓸 필요가 없습니다 . = 5= 1
sebilasse

9
그럴 필요는 없지만 더 표현력이 풍부합니다. 더 나은 IMHO를 만듭니다.
SubliemeSiem

5
그냥이 메모는 문자열 값 열거 작동하지 않습니다
바샤 르 알리 라 바디를

21

쉬운 솔루션. 다음 함수를 사용하여 Enum을 개체 배열로 변환 할 수 있습니다.

 buildGoalProgressMeasurementsArray(): Object[] {

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

밑줄을 제거해야하는 경우 다음과 같이 정규식을 사용할 수 있습니다.

buildGoalProgressMeasurementsArray(): Object[] {

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

8
당신은 유형 번호의 키를 필터링한다 Object.keys(GoalProgressMeasurements) .filter(key => typeof GoalProgressMeasurements[key] === 'number') .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
살바도르 루비오 마르티네즈에게

13

나는 사용한다

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

작업을 수행하는 간단한 한 줄.

간단한 3 단계로 작업을 수행합니다
.-를 사용하여 키와 값의 조합을로드합니다 Object.entries.
-숫자가 아닌 항목을 필터링합니다 (typescript가 역방향 조회에 대한 값을 생성하므로).
-그런 다음 원하는 배열 객체에 매핑합니다.


IE와 프런트 엔드와 호환되지 않습니다 (즉, 지원하지 않아야하는 것은 훌륭한 답변이지만 고객이 생각합니다). 바벨을 증발하는 희망,하지만 난 그것을 확인하지 않은 때문에 다른 접근 방식을 고수
TamusJRoyce을

string enum은 간단합니다.Object.values(GoalProgressMeasurement)
CMS


10
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 2010 년

4

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

다음 함수는 TypeScript 열거 형의 의미를 따라 적절한 키 맵을 값에 제공합니다. 거기에서 객체 배열이나 키 또는 값만 얻는 것은 간단합니다.

/**
 * 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가 열거 형을 거꾸로 생각하고 있음을 지적 할 것입니다. 열거 형의 "키"는 기술적으로 왼쪽에 있고 값은 오른쪽에 있습니다. TypeScript를 사용하면 RHS의 값을 원하는만큼 반복 할 수 있습니다.


4

먼저이 열거 형에 대한 키 배열을 얻습니다. 그런 다음 map () 함수를 사용하여 데이터를 원하는 형식으로 변환합니다. id는 키에서 가져오고 이름은 동일한 키로 enum에서 가져옵니다.

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

2
stackoverflow에 오신 것을 환영합니다. 질문에 답할 때 코드 조각의 기능을 설명하는 것이 좋습니다. 추가 정보를 보려면 여기를 참조하십시오 답변하는 방법
Djensen


답변에 대한 설명이나 세부 사항을 추가해보십시오. 질문에 답할 수는 있지만 답으로 코드를 추가하는 것만으로도 OP 또는 미래의 커뮤니티 구성원이 문제 또는 제안 된 솔루션을 이해하는 데 도움이되지는 않습니다.
Maxim

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

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

왜 이것이 비추천인지 궁금하십니까? 나도 같은 생각을했다. TypeScript가 변경되어 더 이상 enum을 동일한 방식으로 만들지 않을까 걱정할까요?
Tony Smith

1

내가 사용하는 올바른 타이핑이있는 간단한 기능은 다음과 같습니다.

/**
 * Helper to produce an array of enum values.
 * @param enumeration Enumeration object.
 */
export function enumToArray<T, G extends keyof T = keyof T>(enumeration: T): T[G][] {
  // tslint:disable: comment-format

  // enum Colors {
  //   WHITE = 0,
  //   BLACK = 1,
  // }
  // Object.values(Colors) will produce ['WHITE', 'BLACK', 0, 1]

  // So, simply slice the second half
  const enumValues = Object.values(enumeration);
  return enumValues.slice(enumValues.length / 2, enumValues.length) as T[G][];
}

사용 예 :

enum Colors {
  Red = 1,
  Blue = 2,
}
enumToArray(Colors)

멋지네요. 감사!!!
Mauricio Contreras

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

문자열 값이있는 열거 형은 숫자 값이있는 열거 형과 다르므로 @ user8363 솔루션에서 숫자가 아닌 항목을 필터링하는 것이 좋습니다.

다음은 열거 형 문자열, 혼합 수에서 값을 얻는 방법입니다.

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

0

나는 순서가 보장 될 수 있다고 생각하지 않는다. 그렇지 않으면 Object.entries결과의 절반을 잘라 내고 거기에서 매핑 하는 것이 충분히 쉬울 것이다 .

위의 답변에 대한 유일한 (매우 사소한) 문제는

  • 문자열과 숫자 사이에 불필요한 유형 변환이 많이 있습니다.
  • 항목은 단일 반복이 깨끗하고 효과적 일 때 두 번 반복됩니다.
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
}

0
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]);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.