2016-12-23 9 views
4

タイスクリプトの列挙型はどのようにマッピングしますか?例えば、文字列でこれを行うことができます。Map Typescript Enum

let arr = [ 'Hello', 'Goodbye' ]; 

arr.map(v => { 
    if (v === 'Hello') { 
    return ':)'; 
    } else if (v === 'Goodbye') { 
    return ':('; 
    } 
); // [ ':)', ':(' ] 

これ、もちろん、列挙型では動作しません:

enum MyEnum { Hello, Goodbye }; 

MyEnum.map(v => { 
    if (v === MyEnum.Hello) { 
    return ':)'; 
    } else if (v === MyEnum.Goodbye) { 
    return ':('; 
    } 
}); // does not work 

理想的には、私は一般的な方法でこれを行うにしたいと思いますので、私は単純に任意の列挙型を取って、マップ情報に入れて、型情報を保存します。

map(MyEnum, v => { 
    if (v === MyEnum.Hello) { 
    return ':)'; 
    } else if (v === MyEnum.Goodbye) { 
    return ':('; 
    } 
}); // [ ':)', ':(' ] 

私は私のためにこれを行う機能を取得して周りいじるしてきたが、ちょうど右のジェネリックを取得問題を抱えておいてください。使い方は次のようになります。

答えて

2

これを解決する機能は非常に簡単です。あなたが見ることができるように

// you can't use "enum" as a type, so use this. 
type EnumType = { [s: number]: string }; 

function mapEnum (enumerable: EnumType, fn: Function): any[] { 
    // get all the members of the enum 
    let enumMembers: any[] = Object.keys(enumerable).map(key => enumerable[key]); 

    // we are only interested in the numeric identifiers as these represent the values 
    let enumValues: number[] = enumMembers.filter(v => typeof v === "number"); 

    // now map through the enum values 
    return enumValues.map(m => fn(m)); 
} 

は、我々は最初の(MyEnum.Helloは、実行時に実際に1である)、その後、ちょうど上の機能を渡し、それらを通じてマッピング列挙型のキーのすべてを取得する必要があります。それを使用して

は(私は名前を変えたが、あなたの例と同じ)も簡単です:

enum MyEnum { Hello, Goodbye }; 

let results = mapEnum(MyEnum, v => { 
    if (v === MyEnum.Hello) { 
    return ':)'; 
    } else if (v === MyEnum.Goodbye) { 
    return ':('; 
    } 
}); 

console.log(results); // [ ':)', ':(' ] 

我々は唯一の数字であることを列挙型をフィルタリングする必要がある理由があるため通行の列挙型でありますコンパイルされます。

あなたの列挙型は、実際にはこれにコンパイルされます。

var MyEnum; 
(function (MyEnum) { 
    MyEnum[MyEnum["Hello"] = 0] = "Hello"; 
    MyEnum[MyEnum["Goodbye"] = 1] = "Goodbye"; 
})(MyEnum || (MyEnum = {})); 
; 

我々は、実行時にそれらを使用することはできませんとして、我々は"Hello""Goodbye"に興味を持っていませんが。


また、この機能の直前では、面白いtypeという文もあります。これは、someParameter: enumというパラメータを入力できないため、明示的にnumber -> stringというマップを指定する必要があるためです。

+0

これは素晴らしいことであり、実行可能なソリューションに導かれましたが、タイプ情報を保持することには不十分です。いくつかのジェネリックスを追加すると本当に役に立ちます。しかし、[this](http://stackoverflow.com/questions/30774874/enum-as-parameter-in-typescript)によると、列挙型でジェネリックを使用するのはまだtypescriptでは可能ではありません。 –

+0

具体的なタイプ情報はどこですか? –

+0

この関数シグネチャは改善されています: 'function mapEnum (EnumerType、fn:(v:any)=> T):T []'。残念ながら 'v'はまだanyの型を持っています。理想的には、「v」の型は列挙型の型から推定される。残念ながら、これは現在可能なようには見えません。 (私はそれについて間違っているのが大好きです!) –

0

私は一般的にそれを呼び出すことはありませんが、私はこれを何度も使用し、それはあまりにも他の人のために便利になりますことがあります。

type TMyEnum = ':)'|':('; 
class MyEnum { 
    static Hello: TMyEnum = ':)'; 
    static Goodbye: TMyEnum = ':('; 
} 
console.log(MyEnum.Hello); // :) 
console.log(MyEnum.Goodbye); // :(

今、あなたは任意のマッピング機能を必要としないし、期待どおりに持っているしかし、それは動作しますすべての列挙型に別の類似したクラスを作成します(これはあなたが何とかしているので問題ではありません)。今私が考えることができる唯一の欠点は、あなたがそのプロパティを反復することができないということです。しかし今まで私にとっては問題ではありませんでした。私はそれを必要としませんでした。また、必要に応じてクラスに静的配列を追加できます。 ts-enum-utilnpmgithub)で

0

、それが簡単に、タイプセーフな(ジェネリックを使用しています)だと、あなたのための数値の逆引き参照エントリをスキップの面倒を見る:

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

enum MyEnum { Hello, Goodbye }; 

$enum(MyEnum).map(v => { 
    if (v === MyEnum.Hello) { 
     return ':)'; 
    } else if (v === MyEnum.Goodbye) { 
     return ':('; 
    } 
}); // produces [':(', ':)'] 

注:上のベースts-enum-utilは常に反復しますソートされた列挙型キーの順序は、すべての環境で一貫した順序を保証します。オブジェクト。keys()は保証された順序を持っていないので、列挙された列を「クロス・プラットフォームで保証された方法で」定義された順序で反復することは不可能です。

あなたがあなたのマップ機能ですべての可能な列挙型の値を処理することを保証するためにも、より一般的なタイプセーフなコンパイラのチェックのためにts-string-visitornpmgithub)とそれを組み合わせる、その後、文字列の列挙型を使用している場合:

import { $enum } from "ts-enum-util"; 
import { mapString } from "ts-string-visitor"; 

enum MyEnum { Hello = "HELLO", Goodbye = "GOODBYE" }; 

$enum(MyEnum).map(v => { 
    // compiler error if you forget to handle a value, or if you 
    // refactor the enum to have different values, etc. 
    return mapString(v).with({ 
     [MyEnum.Hello]: ':)', 
     [MyEnum.Goodby]: ':(' 
    }); 
}); // produces [':(', ':)'] 
関連する問題