TypeScript numaralandırması nesne dizisine


100

Bu şekilde tanımlanmış bir numaram var:

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

Ancak, API'mizden aşağıdaki gibi bir nesne dizisi / listesi olarak temsil edilmesini istiyorum:

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

Bunu yapmanın kolay ve yerel bir yolu var mı yoksa numaralandırmayı hem bir int hem de bir dizeye çeviren ve nesneleri bir diziye yerleştiren bir işlev mi oluşturmam gerekiyor?


Numaralandırmalar, çalışma zamanında var olan gerçek nesnelerdir. Böylece, şu şekilde bir şey yaparak eşlemeyi tersine çevirebilirsiniz: GoalProgressMeasurements[GoalProgressMeasurements.Completed_Tasks]enum adını elde etmek için. Bunun yardımcı olup olmayacağını bilmiyorum.
Diullei

Yanıtlar:


47

Zor bir bit, TypeScript'in gönderilen nesnedeki numaralandırmayı 'çift' eşlemesi, böylece hem anahtar hem de değer ile erişilebilir olmasıdır.

enum MyEnum {
    Part1 = 0,
    Part2 = 1
}

olarak yayımlanacak

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

Bu nedenle, eşlemeden önce nesneyi filtrelemelisiniz. Yani @Diullei'nin çözümü doğru cevaba sahip. İşte benim uygulamam:

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

Bunu şu şekilde kullanın:

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

console.log(ToArray(GoalProgressMeasurements));

1
mmm eğer enum MyEnum { Part1 = 0, Part2 = 1 }içine dönüşler { Part1: 0, Part2: 1, 0: 'Part1', 1: 'Part2' } sonra, neden zaman console.log(Object.values(MyEnum))sadece sadece 0,1 yazdırır?
Juan José Ramírez

@ JuanJoséRamírez bunu nerede görüyorsun? Benim için Object.values(MyEnum)değerlendirilir["Part1", "Part2", 0, 1]
user8363

Sadece console.log(Object.values(MyEnum))bileşenime yazdırdım . Açısal kullanıyorum, bunun ilişkili olup olmadığından emin değilim. TypeScript konusunda o kadar deneyimli değilim
Juan José Ramírez

davranış farklı TS sürümleriyle değişebilir mi?
Juan José Ramírez

3
Docs typescriptlang.org/docs/handbook/release-notes/… 'yi kontrol ediyorum ve dize numaralandırmalarının farklı bir davranışı var gibi görünüyor. Hiçbir şekilde ters eşleme oluşturmazlar. Kodumda, bu örnekteki dize yerine bir dize sıralaması kullanıyordum.
Juan José Ramírez

40

ES6 kullanıyorsanız

Size verilen numaralandırmanın değer dizisini verecektir .

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

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

Sen alacak colorValueArrayböyle [ 'WHITE', 'BLACK', 'BLUE', 0, 1, 3 ]. Tüm anahtarlar dizinin ilk yarısında ve tüm değerler ikinci yarısında olacaktır.


9
Bunun kopyalar getireceğini unutmayın. Her öğe için dize değeri ve sayısal değer, bu (string | YourEnumType)[]her durumda isteyebileceğiniz bir tür değildir.
Christian Ivicevic

ilk yarının anahtar, ikinci yarının da değerler olacağı garanti ediliyor mu? herhangi bir referans?
Neekey

36

Numaralandırmalar, çalışma zamanında var olan gerçek nesnelerdir. Böylece, şu şekilde bir şey yaparak eşlemeyi tersine çevirebilirsiniz:

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

Buna bağlı olarak aşağıdaki kodu kullanabilirsiniz:

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

Referans: https://www.typescriptlang.org/docs/handbook/enums.html


3
- Sonrasında her şey otomatik olarak +1 = 2olana kadar varsayılanları yazmanıza gerek yoktur . = 5= 1
sebilasse

8
Belki ihtiyacın yok ama bu daha anlamlı. Bu da onu daha iyi IMHO yapar.
SubliemeSiem

5
Sadece bu bir not dize değeri çeteleler için çalışmıyor
Beşar Ali Labadi

21

Kolay Çözüm. Enum'unuzu bir nesne dizisine dönüştürmek için aşağıdaki işlevi kullanabilirsiniz.

 buildGoalProgressMeasurementsArray(): Object[] {

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

Bu alt çizgiyi çıkarmanız gerekirse, normal ifadeyi şu şekilde kullanabiliriz:

buildGoalProgressMeasurementsArray(): Object[] {

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

7
tür numarası anahtarlarını filtrelemelisiniz Object.keys(GoalProgressMeasurements) .filter(key => typeof GoalProgressMeasurements[key] === 'number') .map(key => ({ id: GoalProgressMeasurements[key], name: key }))
Salvador Rubio Martinez

12

kullanırım

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

İşi yapan basit bir 1 satır.

İşi 3 basit adımda yapar
- Kullanarak anahtar ve değer kombinasyonunu yükler Object.entries.
- Sayı olmayanları filtreler (çünkü typcript, ters arama için değerleri oluşturur).
- Sonra onu sevdiğimiz dizi nesnesine eşleriz.


Ön uç ile IE ile uyumlu değil (yani desteklememeli, yani harika bir cevap ... ama sanırım müşteriler).
Babel'in

Bu, dize numaralandırmaları için çalışmaz.
Tony Smith

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
Bu yardımcılar için teşekkür ederim. Çok kullanışlı.
user906573


4

Önce bu enum için bir anahtar dizisi elde ederiz. Ardından, map () işlevini kullanarak verileri istenen formata dönüştürüyoruz. id anahtardan elde edilir, isim aynı anahtar ile numaralandırmadan alınır.

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

2
Stackoverflow'a hoş geldiniz. Soruları yanıtlarken, kod pasajınızın ne yaptığını açıklamak iyi bir fikirdir. Daha fazla bilgi için buraya bakın: Nasıl Cevap
Verilir


Lütfen cevabınıza bazı açıklamalar veya detaylar eklemeyi düşünün. Soruyu yanıtlasa da, yanıt olarak yalnızca bir kod parçası eklemek, OP'nin veya gelecekteki topluluk üyelerinin sorunu veya önerilen çözümü anlamasına yardımcı olmaz.
Maxim

2

Yukarıdaki yanıtların hiçbirini beğenmedim çünkü hiçbiri TypeScript numaralandırmalarındaki değerler olabilecek dizelerin / sayıların karışımını doğru şekilde işlemez.

Aşağıdaki işlev, değerlere anahtarların uygun bir Eşlemini vermek için TypeScript numaralandırmalarının anlamını takip eder. Oradan, bir dizi nesneyi veya yalnızca anahtarları veya yalnızca değerleri elde etmek önemsizdir.

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

Örnek Kullanım:

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

Ayrıca OP'nin numaralandırmaları geriye doğru düşündüğünü de belirteceğim. Numaralandırmadaki "anahtar" teknik olarak sol taraftadır ve değer sağ taraftadır. TypeScript, RHS'deki değerleri istediğiniz kadar tekrarlamanıza izin verir.


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


Lütfen yalnızca kodu yapıştırmak yerine yanıtınızı her zaman bağlama oturtun. Daha fazla ayrıntı için buraya bakın.
gehbiszumeis

0

Bunu şu şekilde yapabilirsiniz:

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"),
}

Ve bunu şu şekilde kullanabilirsiniz:

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'ı ihtiyaç duyduğunuzda nesnenin ek özellikleriyle genişletebilirsiniz. Bu yaklaşımı, bir değerden daha fazlasını içeren bir nesne olması gereken her numaralandırma için kullanıyorum.


0

Strings değerine sahip numaralandırmalar, sayı değerlerine sahip olanlardan farklı olduğundan, olmayan sayıları @ user8363 çözümünden filtrelemek daha iyidir.

İşte dizelerden, karma sayılardan değer almanın yolu:

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

Bir TypeScript iş parçacığında hiç kimsenin desteklenen yazımla geçerli TypeScript işlevi vermediğine şaşırdım. İşte @ user8363 çözümünün varyasyonu:

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

Basit bir çözüm var, Bu yüzden çalıştırdığınızda Object.keys(Enum), size bir Değerler ve Anahtarlar Dizisi verecek, ilk dilim Değerler ve ikinci anahtarlar, öyleyse neden sadece ikinci dilimi döndürmiyoruz, aşağıdaki kod benim için çalışıyor .

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

Bunun neden reddedildiğini merak mı ediyorsunuz? Ben de aynı fikirdeydim. TypeScript'in değişeceği ve artık aynı şekilde numaralandırmayacağı endişesi olur mu?
Tony Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.