TypeScriptで文字列を列挙型に変換するにはどうすればよいですか?


312

TypeScriptで次の列挙型を定義しました。

enum Color{
    Red, Green
}

今私の関数では、文字列として色を受け取ります。私は次のコードを試しました:

var green= "Green";
var color : Color = <Color>green; // Error: can't convert string to enum

その値を列挙型に変換するにはどうすればよいですか?

回答:


431

TypeScript 0.9の列挙型は文字列+数値ベースです。単純な変換では型アサーションは必要ありません。

enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green];

オンラインでお試しください

私のOSSブックには、これと他のEnumパターンに関するドキュメントがあります。https//basarat.gitbook.io/typescript/type-system/enums


112
これは機能しません--noImplicitAny(VSではチェックされていない「暗黙の 'any'タイプを許可する」)。それはerror TS7017: Index signature of object type implicitly has an 'any' type.私にとってこれは機能しました:(var color: Color = (<any>Color)[green];バージョン1.4でテスト済み)
Vojta

3
@ヴォイタは正しいと言った。VS 2012では機能しません。これは機能しましたが、var color:Color =(<any> Color)[green];
ファイサルMq

3
これは、公式ドキュメントがあることを確認するために思える、ここでも動作しません:typescriptlang.org/docs/handbook/release-notes/...
ピーテル・デ・ビエ

26
if --noImplicitAny var color : Color = Color[green as keyof typeof Color];
Jonas

2
@ Naxos84私のanswearをご覧くださいstackoverflow.com/a/56076148/294242
Jonas

123

Typescript 2.1以降、列挙型の文字列キーは強く型付けされています。 keyof typeof使用可能な文字列キーに関する情報を取得するために使用されます(1):

enum Color{
    Red, Green
}

let typedColor: Color = Color.Green;
let typedColorString: keyof typeof Color = "Green";

// Error "Black is not assignable ..." (indexing using Color["Black"] will return undefined runtime)
typedColorString = "Black";

// Error "Type 'string' is not assignable ..." (indexing works runtime)
let letColorString = "Red";
typedColorString = letColorString;

// Works fine
typedColorString = "Red";

// Works fine
const constColorString = "Red";
typedColorString = constColorString

// Works fine (thanks @SergeyT)
let letColorString = "Red";
typedColorString = letColorString as keyof typeof Color;

typedColor = Color[typedColorString];

https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types


4
タイプキャストを使用できます:let s = "Green"; let typedColor = <keyof typeof Color> s;
SergeyT

うん、と置き換えるletconstキャストせずに動作します。これを明確にするために例を更新しました。ありがとう@SergeyT
ビクター

1
typedColorString = Color["Black"];今すぐ戻るerror TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'
ドミニク

2
1行の回答:const color: Color = Color[colorString as keyof typeof Color];
cscan

38

入力文字列がColor enumと完全に一致することが確実な場合は、次のように使用します。

const color: Color = (<any>Color)["Red"];

入力文字列がEnumと一致しない場合は、次を使用します。

const mayBeColor: Color | undefined = (<any>Color)["WrongInput"];
if (mayBeColor !== undefined){
     // TypeScript will understand that mayBeColor is of type Color here
}

遊び場


私たちはキャストしない場合enum<any>、次に入力する活字体は、エラーが表示されます:

インデックス式のタイプが「number」ではないため、要素は暗黙的に「any」タイプを持っています。

つまり、デフォルトでは、TypeScriptのEnum型は数値インデックスで機能しますが、 let c = Color[0]などの文字列インデックスでは機能しませんlet c = Color["string"]。これは、より一般的な問題であるオブジェクト文字列インデックスに対するMicrosoftチームの既知の制限です。


<keyof typeof Color>にキャストすることもできます。また、「0」も間違った入力ですが、未定義は返されないので、typeof mayBeColor === 'number'を確認してください
Quentin 2

@ Quentin2数値文字列はどうですか?つまり、そうでtypeof '0'なければなりませんstring
Patrick Michaelsen

36
enum Color{
    Red, Green
}

// To String
 var green: string = Color[Color.Green];

// To Enum / number
var color : Color = Color[green as keyof typeof Color]; //Works with --noImplicitAny

この例--noImplicitAnyはTypeScriptで動作します

出典:
https : //github.com/Microsoft/TypeScript/issues/13775#issuecomment-276381229 https://www.typescriptlang.org/docs/handbook/advanced-types.html#index-types


理由はわかりませんが、このソリューションはconst enumでは機能しません (Typescript 3.8.3を使用)
Robin-Hoodie

30

このメモは元の質問ではなく、バサラトの回答に関連しています。

自分のプロジェクトで奇妙な問題がありました。コンパイラーは、このコードと同等のコードを使用して、「文字列をColorに変換できません」とほぼ同等のエラーを出していました。

var colorId = myOtherObject.colorId; // value "Green";
var color: Color = <Color>Color[colorId]; // TSC error here: Cannot convert string to Color.

コンパイラ型の推論が混乱していることcolorIdがわかり、それは列挙値でありIDではないと考えました。問題を解決するには、IDを文字列としてキャストする必要がありました。

var colorId = <string>myOtherObject.colorId; // Force string value here
var color: Color = Color[colorId]; // Fixes lookup here.

問題の原因はわかりませんが、同じ問題が発生した場合に備えて、ここにこのメモを残しておきます。


ありがとうございました!これはかなりばかげた問題であり、問​​題が何であるかを理解することは困難です。
ChickenFeet

25

次のコードを使用して動作させました。

var green= "Green";
var color : Color= <Color>Color[green];

23

enumに文字列値を提供する場合、ストレートキャストは問題なく機能します。

enum Color {
  Green = "Green",
  Red = "Red"
}

const color = "Green";
const colorEnum = color as Color;

1
とてもシンプル。いいね!
ベルヌーイIT

1
無効な色を保護しないため、誤解を招く可能性があります。 const colorEnum = "Blue" as Colorエラーは発生せず、問題ないと思われますcolorEnum。しかし、それを行うconsole.logと、「青」が表示されます。 Artruの答えは素晴らしいです。なぜなら、そうcolorEnumなるでしょうundefined-そして、それを具体的に確認することができます。
Mファランガ

20

typescriptを使用する場合:上記の解決策の多くは機能しないか、過度に複雑になる可能性があります。

状況:文字列が列挙値と同じではない(大文字と小文字が異なる)

enum Color {
  Green = "green",
  Red = "red"
}

ただ使用する:

const color = "green" as Color

15

また、同じコンパイラエラーが発生しました。Sly_cardinalのアプローチの少し短いバリエーション。

var color: Color = Color[<string>colorId];

追加として:enumを文字列としてシリアル化したjavascriptレイヤーによって埋められたtypescript enumがある場合(たとえば、AngularJSを介したAsp Web API)、myProp.color = Color[<string><any>myProp.color] Cheers
Victor

1
これは認められた答えでなければなりません。
ミロスラフポポフ

9

TypeScriptコンパイラが変数のタイプが文字列であることを知っている場合、これは機能します。

let colorName : string = "Green";
let color : Color = Color[colorName];

それ以外の場合は、明示的に文字列に変換する必要があります(コンパイラの警告を回避するため)。

let colorName : any = "Green";
let color : Color = Color["" + colorName];

実行時に両方のソリューションが機能します。


3
<string>colorName代わりにタイプキャストを使用しないのはなぜ"" + colorNameですか?
SergeyT 2017年

7

この質問にはさまざまな情報が混在しているため、TypeScript を使用したモデルでの列挙型の使用に関するNickのガイドの TypeScript 2.x +の実装全体について説明します。

このガイドは、クライアント側のEnumとして便利にモデル化されるサーバーから一連の既知の文字列を取り込むクライアント側コードを作成しているユーザーを対象としています。

列挙型を定義する

列挙型から始めましょう。次のようになります。

export enum IssueType {
  REPS = 'REPS',
  FETCH = 'FETCH',
  ACTION = 'ACTION',
  UNKNOWN = 'UNKNOWN',
}

ここで2つの注意点があります。

  1. これらを文字列で裏付けられた列挙型ケースとして明示的に宣言しているため、他の無関係な数値ではなく、文字列でインスタンス化できます。

  2. サーバーモデルに存在するオプションと存在しないオプションを追加しました:UNKNOWN。これはundefined好みに応じて処理できますが、| undefined処理を簡略化するために、可能な場合は型を避けたいと思います。

UNKNOWNケースがあることの素晴らしい点は、コードでそれを本当に明確にして、不明な列挙型のケースのスタイルを真っ赤に点滅させて、何かを正しく処理していないことがわかるということです。

列挙型を解析する

別のモデルに埋め込まれたこの列挙型を使用するか、すべてを単独で使用する可能性がありますが、JSONまたはXML(ha)から文字列型の列挙型を解析して、厳密に型指定された対応するものにする必要があります。別のモデルに埋め込まれた場合、このパーサーはクラスコンストラクターに存在します。

parseIssueType(typeString: string): IssueType {
  const type = IssueType[typeString];
  if (type === undefined) {
    return IssueType.UNKNOWN;
  }

  return type;
}

enumが適切に解析されると、最終的に適切な型になります。それ以外の場合は、それを受け取り、undefined傍受してUNKNOWNケースを返すことができます。undefined不明なケースとして使用したい場合は、試行された列挙型解析の結果を返すことができます。

そこからは、解析関数を使用し、新しく強く型付けされた変数を使用するだけです。

const strongIssueType: IssueType = parseIssueType('ACTION');
// IssueType.ACTION
const wrongIssueType: IssueType = parseIssueType('UNEXPECTED');
// IssueType.UNKNOWN

6
残念ながら、これは正しくない、または少なくとも一般化できないようです。キーが割り当てられた文字列と同じであるため、機能します。しかし、私の場合のように、それらが異なる場合、これは機能しません。ドキュメントの言葉で:「文字列の列挙型メンバーは、生成された逆マッピングをまったく取得しないことに注意してください。」コードはのようにコンパイルされますIssueType["REPS"]="REPS"。enumを少し異なるように定義した場合、たとえば、REPS="reps"これにより次のIssueType["REPS"]="reps"いずれかが得られます...
高積雲

... 列挙IssueType.UNKNOWNにはキーがないため、常に戻りrepsます。文字列にハイフンが含まれているため、キーとして使用できないため、問題が解決しませんでした。
高積雲

最後に、これが文字列列挙型ではないことをコンパイラに納得させることで、この回答の解決策を見つけました。この情報をあなた自身の答えに編集する価値があるかもしれません。
高積雲

7

私はenumからを得ることができる答えを探していましたstringが、私の場合、列挙値には対応する異なる文字列値がありました。OPにはの単純な列挙型がColorありましたが、私には別のものがありました。

enum Gender {
  Male = 'Male',
  Female = 'Female',
  Other = 'Other',
  CantTell = "Can't tell"
}

文字列で解決しようとするGender.CantTell"Can't tell"、それが返されますundefinedオリジナル答えを。

別の答え

基本的に、私はこの答えに強く触発された別の答えを思いつきました:

export const stringToEnumValue = <ET, T>(enumObj: ET, str: string): T =>
  (enumObj as any)[Object.keys(enumObj).filter(k => (enumObj as any)[k] === str)[0]];

ノート

  • 私たちは取る最初の結果のをfilterクライアントがenumからの有効な文字列を渡していると仮定すると、。そうでない場合は、undefined返されます。
  • TypeScript 3.0+(現在TypeScript 3.5を使用)では、として解決されるため、にキャストenumObjします。anyenumObjunknown

使用例

const cantTellStr = "Can't tell";

const cantTellEnumValue = stringToEnumValue<typeof Gender, Gender>(Gender, cantTellStr);
console.log(cantTellEnumValue); // Can't tell

注:そして、誰かがコメントで指摘したように、私は noImplicitAny

更新版

キャストなしany、適切なタイピング。

export const stringToEnumValue = <T, K extends keyof T>(enumObj: T, value: string): T[keyof T] | undefined =>
  enumObj[Object.keys(enumObj).filter((k) => enumObj[k as K].toString() === value)[0] as keyof typeof enumObj];

また、更新されたバージョンはそれを呼び出す簡単な方法があり、より読みやすくなっています。

stringToEnumValue(Gender, "Can't tell");

6

列挙型の値をループする方法を知る必要があり(いくつかの列挙型の多くの順列をテストしていた)、これがうまくいくことがわかりました。

export enum Environment {
    Prod = "http://asdf.com",
    Stage = "http://asdf1234.com",
    Test = "http://asdfasdf.example.com"
}

Object.keys(Environment).forEach((environmentKeyValue) => {
    const env = Environment[environmentKeyValue as keyof typeof Environment]
    // env is now equivalent to Environment.Prod, Environment.Stage, or Environment.Test
}

ソース:https : //blog.mikeski.net/development/javascript/typescript-enums-to-from-string/


この答えは天才です!大好きです。特に、文字列から列挙型を作成する方法。これにより、列挙型やその他のケースをテストするときの入力作業が大幅に削減されます。
Florian Leitgeb

はい、私はこれをJestで使用して、each1つのメソッドですべての列挙型のケースをテストします
mikeb

3

列挙型

enum MyEnum {
    First,
    Second,
    Three
}

使用例

const parsed = Parser.parseEnum('FiRsT', MyEnum);
// parsed = MyEnum.First 

const parsedInvalid= Parser.parseEnum('other', MyEnum);
// parsedInvalid = undefined

大文字と小文字を区別する解析を無視します

class Parser {
    public static parseEnum<T>(value: string, enumType: T): T[keyof T] | undefined {
        if (!value) {
            return undefined;
        }

        for (const property in enumType) {
            const enumMember = enumType[property];
            if (typeof enumMember === 'string') {
                if (enumMember.toUpperCase() === value.toUpperCase()) {
                    const key = enumMember as string as keyof typeof enumType;
                    return enumType[key];
                }
            }
        }
        return undefined;
    }
}

私のような列挙型を持っている人は誰でもreturn enumType[property];、列挙型アイテムが次のようになっている場合はケースに入れるべきですSkills = "anyvalue"
neustart47

@ neustart47質問してください。
ОчирДармаев

それは問題ではありません。私は同じケースを探している人のためにいくつかの変更を述べました。正解です。
neustart47

2

作成した列挙型は、フォワードマッピング(name -> value)とリバース(value -> name)マッピングの両方を格納するオブジェクトにコンパイルされます。このクロムdevtoolsスクリーンショットから観察できるように:

ここに画像の説明を入力してください

デュアルマッピングの仕組みと、あるマッピングから別のキャストにキャストする方法の例を次に示します。

enum Color{
    Red, Green
}
// To Number
var greenNr: number = Color['Green'];
console.log(greenNr); // logs 1

// To String
var greenString: string = Color[Color['Green']];  // or Color[Color[1]
console.log(greenString); // logs Green

// In your example

// recieve as Color.green instead of the string green
var green: string = Color[Color.Green];  

// obtain the enum number value which corresponds to the Color.green property
var color: Color = (<any>Color)[green];  

console.log(color); // logs 1

1

これを試して

var color:Color =(任意の色)["Green];

3.5.3バージョンでは問題なく動作します


0

名前空間を使用して列挙型の機能を拡張している場合は、次のようなこともできます

    enum Color {
        Red, Green
    }

    export namespace Color {
      export function getInstance(color: string) : Color {
        if(color == 'Red') {
          return Color.Red;
        } else if (color == 'Green') {
          return Color.Green;
        }
      }
    }

このように使用します

  Color.getInstance('Red');

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.