TypeScript - צור Enum עם ערכי מחרוזת


הקוד הבא יכול לשמש ליצירת enum ב-TypeScript:

enum e {
    hello = 1,
    world = 2
};

והערכים ניתנים לגישה על ידי:

e.hello;
e.world;

איך אני יוצר enum עם ערכי מחרוזת?

enum e {
    hello = "hello", // error: cannot convert string to e
    world = "world"  // error 
};

תשובה #1

TypeScript 2.4

כעת ישנם enums של מחרוזות כך שהקוד שלך פשוט עובד:

enum E {
    hello = "hello",
    world = "world"
};

🌹

TypeScript 1.8

מאז TypeScript 1.8 ניתן להשתמש בסוגי מחרוזת מילולית כדי לספק חוויה אמינה ובטוחה עבור ערכי מחרוזת ממוספרים (שזה חלקית למה שמשתמשים במקראי enum).

type Options = "hello" | "world";
var foo: Options;
foo = "hello"; // Okay 
foo = "asdf"; // Error!

עוד: https://www.typescriptlang.org/docs/handbook/advanced-types.html#string-literal-types

תמיכה במערכת ישנה

אנומס ב-TypeScript מבוססים על מספרים.

אתה יכול להשתמש במחלקה עם חברים סטטיים אך:

class E
{
    static hello = "hello";
    static world = "world"; 
}

אתה יכול ללכת על פשטות גם כן:

var E = {
    hello: "hello",
    world: "world"
}

עדכון: בהתבסס על הדרישה להיות מסוגל לעשות משהו כמו var test:E=E.hello; הדברים הבאים עומדים בכך:

class E
{
    // boilerplate 
    constructor(public value:string){    
    }

    toString(){
        return this.value;
    }

    // values 
    static hello = new E("hello");
    static world = new E("world");
}

// Sample usage: 
var first:E = E.hello;
var second:E = E.world;
var third:E = E.hello;

console.log("First value is: "+ first);
console.log(first===third); 

תשובה #2

בגרסה האחרונה (1.0RC) של TypeScript, ניתן להשתמש ב-enums כך:

enum States {
    New,
    Active,
    Disabled
} 

// this will show message '0' which is number representation of enum member
alert(States.Active); 

// this will show message 'Disabled' as string representation of enum member
alert(States[States.Disabled]);

עדכון 1

כדי לקבל את הערך המספרי של חבר enum מתוך ערך מחרוזת, ניתן להשתמש בזה:

var str = "Active";
// this will show message '1'
alert(States[str]);

עדכון 2

ב-TypeScript 2.4 האחרון, הוצגו enums מסוג מחרוזת, כך:

enum ActionType {
    AddUser = "ADD_USER",
    DeleteUser = "DELETE_USER",
    RenameUser = "RENAME_USER",

    // Aliases
    RemoveUser = DeleteUser,
}

למידע נוסף על TypeScript 2.4, קראו את הבלוג ב-MSDN.

תשובה #3

TypeScript 2.4+

כעת אתה יכול להקצות ערכי מחרוזת ישירות לחברי האנומ:

enum Season {
    Winter = "winter",
    Spring = "spring",
    Summer = "summer",
    Fall = "fall"
}

ראה את #15486 למידע נוסף.

TypeScript 1.8+

ב-TypeScript 1.8 ומעלה, ניתן ליצור טיפוס מחרוזת כדי להגדיר את הטיפוס ואובייקט עם אותו שם עבור רשימת הערכים. זה מחקה את ההתנהגות הצפויה של enum מחרוזת.

הנה דוגמה:

type MyStringEnum = "member1" | "member2";

const MyStringEnum = {
    Member1: "member1" as MyStringEnum,
    Member2: "member2" as MyStringEnum
};

שיעבוד כמו מחרוזת של enum:

// implicit typing example
let myVariable = MyStringEnum.Member1; // ok
myVariable = "member2";                // ok
myVariable = "some other value";       // error, desired

// explict typing example
let myExplicitlyTypedVariable: MyStringEnum;
myExplicitlyTypedVariable = MyStringEnum.Member1; // ok
myExplicitlyTypedVariable = "member2";            // ok
myExplicitlyTypedVariable = "some other value";   // error, desired

ודא להקליד את כל המחרוזות באובייקט! אם לא תעשה זאת, בדוגמה הראשונה למעלה המשתנה לא יקבל טיפוס מרומז של MyStringEnum.

תשובה #4

ב-TypeScript 0.9.0.1, למרות שמתרחשת שגיאת קומפיילר, הקומפיילר עדיין יכול לקמפל את קובץ ה-ts לקובץ js. הקוד עובד כפי שציפינו ו-Visual Studio 2012 יכול לתמוך בהשלמת קוד אוטומטית.

עדכון :

בסינטקס, TypeScript לא מאפשרת לנו ליצור enum עם ערכי מחרוזת, אבל אנחנו יכולים להערים על הקומפיילר :p

enum Link
{
    LEARN   =   <any>'/Tutorial',
    PLAY    =   <any>'/Playground',
    GET_IT  =   <any>'/#Download',
    RUN_IT  =   <any>'/Samples',
    JOIN_IN =   <any>'/#Community'
}

alert('Link.LEARN:    '                     + Link.LEARN);
alert('Link.PLAY:    '                      + Link.PLAY);
alert('Link.GET_IT:    '                    + Link.GET_IT);
alert('Link[\'/Samples\']:    Link.'        + Link['/Samples']);
alert('Link[\'/#Community\']    Link.'      + Link['/#Community']);

מִגרָשׂ מְשָׂחָק

תשובה #5

TypeScript 2.1 +

סוגי חיפוש, שהוצגו ב-TypeScript 2.1, מאפשרים דפוס נוסף לדימוי משתנים מסוג מחרוזת:

// String enums in TypeScript 2.1
const EntityType = {
    Foo: 'Foo' as 'Foo',
    Bar: 'Bar' as 'Bar'
};

function doIt(entity: keyof typeof EntityType) {
    // ...
}

EntityType.Foo          // 'Foo'
doIt(EntityType.Foo);   // 👍
doIt(EntityType.Bar);   // 👍
doIt('Foo');            // 👍
doIt('Bar');            // 👍
doIt('Baz');            // 🙁 

TypeScript 2.4 +

עם גרסה 2.4, TypeScript הציגה תמיכה מקורית באנומים של מחרוזות, ולכן הפתרון שלמעלה אינו נדרש. מתוך התיעוד של TS:

enum Colors {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE",
}

תשובה #6

למה לא פשוט להשתמש בדרך המקומית לגישה למחרוזות של enum.

enum e {
  WHY,
  NOT,
  USE,
  NATIVE
}

e[e.WHY] // this returns string 'WHY'

תשובה #7

אתה יכול להשתמש במנויי מחרוזת ב-TypeScript האחרון:

enum e
{
    hello = <any>"hello",
    world = <any>"world"
};

מקור: https://blog.rsuter.com/how-to-implement-an-enum-with-string-values-in-typescript/

עדכון - 2016

דרך מעט יותר חזקה ליצור סט של מחרוזות שאני משתמש בהן עבור React בימים אלו היא כזו:

export class Messages
{
    static CouldNotValidateRequest: string = 'There was an error validating the request';
    static PasswordMustNotBeBlank: string = 'Password must not be blank';   
}

import {Messages as msg} from '../core/messages';
console.log(msg.PasswordMustNotBeBlank);

תשובה #8

עדכון: TypeScript 3.4

אתה יכול פשוט להשתמש ב-as const:

const AwesomeType = {
   Foo: "foo",
   Bar: "bar"
} as const;

TypeScript 2.1

זה גם ניתן לעשות כך. מקווה שזה יעזור למישהו.

const AwesomeType = {
    Foo: "foo" as "foo",
    Bar: "bar" as "bar"
};

type AwesomeType = (typeof AwesomeType)[keyof typeof AwesomeType];

console.log(AwesomeType.Bar); // returns bar
console.log(AwesomeType.Foo); // returns foo

function doSth(awesometype: AwesomeType) {
    console.log(awesometype);
}

doSth("foo") // return foo
doSth("bar") // returns bar
doSth(AwesomeType.Bar) // returns bar
doSth(AwesomeType.Foo) // returns foo
doSth('error') // does not compile

תשובה #9

הנה פתרון די נקי שמאפשר הירושה, באמצעות TypeScript 2.0. לא ניסיתי את זה בגרסה קודמת.

בונוס: הערך יכול להיות כל סוג!

export class Enum<T> {
  public constructor(public readonly value: T) {}
  public toString() {
    return this.value.toString();
  }
}

export class PrimaryColor extends Enum<string> {
  public static readonly Red = new Enum('#FF0000');
  public static readonly Green = new Enum('#00FF00');
  public static readonly Blue = new Enum('#0000FF');
}

export class Color extends PrimaryColor {
  public static readonly White = new Enum('#FFFFFF');
  public static readonly Black = new Enum('#000000');
}

// Usage:

console.log(PrimaryColor.Red);
// Output: Enum { value: '#FF0000' }
console.log(Color.Red); // inherited!
// Output: Enum { value: '#FF0000' }
console.log(Color.Red.value); // we have to call .value to get the value.
// Output: #FF0000
console.log(Color.Red.toString()); // toString() works too.
// Output: #FF0000

class Thing {
  color: Color;
}

let thing: Thing = {
  color: Color.Red,
};

switch (thing.color) {
  case Color.Red: // ...
  case Color.White: // ...
}