Создание перечисления со строковыми значениями в TypeScript
следующий код может быть использован для создания перечисления в TypeScript:
enum e {
hello = 1,
world = 2
};
и значения могут быть доступны по :
e.hello;
e.world;
как создать перечисление со строковыми значениями ?
enum e {
hello = "hello", // error: cannot convert string to e
world = "world" // error
};
27 ответов
машинопись 2.4
теперь есть перечисления строк, поэтому ваш код просто работает:
enum E {
hello = "hello",
world = "world"
};
машинопись 1.8
поскольку TypeScript 1.8 вы можете использовать строковые литералы, чтобы обеспечить надежный и безопасный опыт для именованных строковых значений (для чего частично используются перечисления).
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);
в последней версии (1.0 RC) TypeScript, вы можете использовать перечисления, как это:
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
чтобы получить числовое значение члена перечисления из строкового значения, вы можете использовать это:
var str = "Active";
// this will show message '1'
alert(States[str]);
обновление 2
в последнем TypeScript 2.4 было введено перечисление строк, например:
enum ActionType {
AddUser = "ADD_USER",
DeleteUser = "DELETE_USER",
RenameUser = "RENAME_USER",
// Aliases
RemoveUser = DeleteUser,
}
для получения дополнительной информации о TypeScript 2.4 прочитайте блог на MSDN.
TypeScript 2.4+
теперь вы можете назначить строковых значений в enum члены:
enum Season {
Winter = "winter",
Spring = "spring",
Summer = "summer",
Fall = "fall"
}
посмотреть #15486 для получения дополнительной информации.
TypeScript 1.8+
в TypeScript 1.8+ можно создать строковый литерал для определения типа и объекта с одинаковым именем для списка значений. Он имитирует ожидаемое поведение перечисления строк.
вот пример:
type MyStringEnum = "member1" | "member2";
const MyStringEnum = {
Member1: "member1" as MyStringEnum,
Member2: "member2" as MyStringEnum
};
который будет работать как перечисление строку:
// 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
.
в TypeScript 0.9.0.1, хотя это происходит ошибка компилятора, компилятор все еще может скомпилировать файл ts в файл js. Код работает так, как мы ожидали, и Visual Studio 2012 может поддерживать автоматическое завершение кода.
обновление :
в синтаксисе TypeScript не позволяет нам создавать перечисление со строковыми значениями, но мы можем взломать компилятор :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']);
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('Bad'); //
TypeScript 2.4+
С версией 2.4 TypeScript представила встроенную поддержку перечислений строк, поэтому решение выше не требуется. Из документов TS:
enum Colors {
Red = "RED",
Green = "GREEN",
Blue = "BLUE",
}
почему бы просто не использовать собственный способ доступа к строкам перечисления.
enum e {
WHY,
NOT,
USE,
NATIVE
}
e[e.WHY] // this returns string 'WHY'
вы можете использовать перечисления строк в последнем 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);
вот довольно чистое решение, которое позволяет наследование, используя 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: // ...
}
хакерский способ это: -
CallStatus.ТС
enum Status
{
PENDING_SCHEDULING,
SCHEDULED,
CANCELLED,
COMPLETED,
IN_PROGRESS,
FAILED,
POSTPONED
}
export = Status
Utils.ТС
static getEnumString(enum:any, key:any):string
{
return enum[enum[key]];
}
как использовать
Utils.getEnumString(Status, Status.COMPLETED); // = "COMPLETED"
это работает для меня:
class MyClass {
static MyEnum: { Value1; Value2; Value3; }
= {
Value1: "Value1",
Value2: "Value2",
Value3: "Value3"
};
}
или
module MyModule {
export var MyEnum: { Value1; Value2; Value3; }
= {
Value1: "Value1",
Value2: "Value2",
Value3: "Value3"
};
}
8)
Update: вскоре после публикации этого я обнаружил другой способ, но забыл опубликовать обновление (однако кто-то уже упоминал об этом выше):
enum MyEnum {
value1 = <any>"value1 ",
value2 = <any>"value2 ",
value3 = <any>"value3 "
}
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
Я просто объявляю интерфейс и использую переменную этого типа для доступа к перечислению. Сохранение интерфейса и перечисления в синхронизации на самом деле легко, так как TypeScript жалуется, если что-то меняется в перечислении, например.
ошибка TS2345: аргумент типа 'typeof EAbFlagEnum' не присваивается к параметру типа 'IAbFlagEnum'. Свойство 'Move' отсутствует в типе 'typeof на EAbFlagEnum'.
преимущество этого метода приведение типов не требуется чтобы использовать перечисление (интерфейс) в различных ситуациях, и, таким образом, поддерживается больше типов ситуаций, таких как переключатель/случай.
// Declare a TypeScript enum using unique string
// (per hack mentioned by zjc0816)
enum EAbFlagEnum {
None = <any> "none",
Select = <any> "sel",
Move = <any> "mov",
Edit = <any> "edit",
Sort = <any> "sort",
Clone = <any> "clone"
}
// Create an interface that shadows the enum
// and asserts that members are a type of any
interface IAbFlagEnum {
None: any;
Select: any;
Move: any;
Edit: any;
Sort: any;
Clone: any;
}
// Export a variable of type interface that points to the enum
export var AbFlagEnum: IAbFlagEnum = EAbFlagEnum;
использование переменной, а не перечисления, дает желаемые результаты.
var strVal: string = AbFlagEnum.Edit;
switch (strVal) {
case AbFlagEnum.Edit:
break;
case AbFlagEnum.Move:
break;
case AbFlagEnum.Clone
}
флаги были еще одной необходимостью для меня, поэтому я создал модуль NPM, который добавляет к этому примеру и включает тесты.
с изготовленными на заказ трансформаторами (https://github.com/Microsoft/TypeScript/pull/13940), который доступен в typescript@next, вы можете создать перечисление как объект со строковыми значениями из строковых литералов.
пожалуйста, посмотрите в мой пакет npm,ТС-трансформатор-перечислить.
пример использования:
// The signature of `enumerate` here is `function enumerate<T extends string>(): { [K in T]: K };`
import { enumerate } from 'ts-transformer-enumerate';
type Colors = 'green' | 'yellow' | 'red';
const Colors = enumerate<Colors>();
console.log(Colors.green); // 'green'
console.log(Colors.yellow); // 'yellow'
console.log(Colors.red); // 'red'
TypeScript
/** Utility function to create a K:V from a list of strings */
function strEnum<T extends string>(o: Array<T>): {[K in T]: K} {
return o.reduce((res, key) => {
res[key] = key;
return res;
}, Object.create(null));
}
/**
* Sample create a string enum
*/
/** Create a K:V */
const Direction = strEnum([
'North',
'South',
'East',
'West'
])
/** Create a Type */
type Direction = keyof typeof Direction;
/**
* Sample using a string enum
*/
let sample: Direction;
sample = Direction.North; // Okay
sample = 'North'; // Okay
sample = 'AnythingElse'; // ERROR!
от https://basarat.gitbooks.io/typescript/docs/types/literal-types.html
к исходной ссылке вы можете найти более простые способы выполнения строкового литерала типа
там много ответов, но я не вижу никаких полных решений. Проблема с принятым ответом, а также enum { this, one }
, это то, что он рассеивает строковое значение, которое вы используете во многих файлах. Мне тоже не нравится "обновление", оно сложное и не использует типы. Я думаю ответ Майкла Бромли наиболее правильно, но это интерфейс немного хлопот и может сделать с типом.
Я использую TypeScript 2.0.* Вот что я сделал бы
export type Greeting = "hello" | "world";
export const Greeting : { hello: Greeting , world: Greeting } = {
hello: "hello",
world: "world"
};
let greet: Greeting = Greeting.hello
Он также имеет гораздо более приятную информацию типа / наведения при использовании полезной IDE. Недостаток в том, что вам нужно написать строки дважды, но, по крайней мере, это только в двух местах.
@basarat это было здорово. Вот упрощенный, но немного расширенный пример, который вы можете использовать:
export type TMyEnumType = 'value1'|'value2';
export class MyEnumType {
static VALUE1: TMyEnumType = 'value1';
static VALUE2: TMyEnumType = 'value2';
}
console.log(MyEnumType.VALUE1); // 'value1'
const variable = MyEnumType.VALUE2; // it has the string value 'value2'
switch (variable) {
case MyEnumType.VALUE1:
// code...
case MyEnumType.VALUE2:
// code...
}
недавно столкнулся с этой проблемой с TypeScript 1.0.1 и решил так:
enum IEvents {
/** A click on a product or product link for one or more products. */
CLICK,
/** A view of product details. */
DETAIL,
/** Adding one or more products to a shopping cart. */
ADD,
/** Remove one or more products from a shopping cart. */
REMOVE,
/** Initiating the checkout process for one or more products. */
CHECKOUT,
/** Sending the option value for a given checkout step. */
CHECKOUT_OPTION,
/** The sale of one or more products. */
PURCHASE,
/** The refund of one or more products. */
REFUND,
/** A click on an internal promotion. */
PROMO_CLICK
}
var Events = [
'click',
'detail',
'add',
'remove',
'checkout',
'checkout_option',
'purchase',
'refund',
'promo_click'
];
function stuff(event: IEvents):boolean {
// event can now be only IEvents constants
Events[event]; // event is actually a number that matches the index of the array
}
// stuff('click') won't work, it needs to be called using stuff(IEvents.CLICK)
Я думаю, вы должны попробовать с этим,в этом случае значение переменной не изменится, и она работает совсем как перечисления, используя как класс, также работает единственный недостаток-по ошибке вы можете изменить значение статической переменной, и это то, что мы не хотим в перечислениях.
namespace portal {
export namespace storageNames {
export const appRegistration = 'appRegistration';
export const accessToken = 'access_token';
}
}
Я придумал такое решение:
// Utils.ts
export function convertEnumValuesToString(obj) {
Object.keys(obj).forEach(function (key) {
if (isNaN(+key)) {
Object.defineProperty(obj, key, {
value: key,
enumerable: true
});
}
});
return obj;
}
// actions/hello.ts
import { convertEnumValuesToString } from '../utils'
export enum actionTypes {
GREETING,
FAREWELL_INIT,
FAREWELL_DONE
}
console.log(actionTypes .GREETING) // 0
convertEnumValuesToString(actionTypes); // override to same key-based string values
console.log(actionTypes .GREETING) // "GREETING"
//to access the enum with its string value you can convert it to object
//then you can convert enum to object with proberty
//for Example :
enum days { "one" =3, "tow", "Three" }
let _days: any = days;
if (_days.one == days.one)
{
alert(_days.one + ' | ' + _days[4]);
}
Если то, что вы хотите, в основном простая отладка (с проверкой типа) и не нужно указывать специальные значения для перечисления, это то, что я делаю:
export type Enum = { [index: number]: string } & { [key: string]: number } | Object;
/**
* inplace update
* */
export function enum_only_string<E extends Enum>(e: E) {
Object.keys(e)
.filter(i => Number.isFinite(+i))
.forEach(i => {
const s = e[i];
e[s] = s;
delete e[i];
});
}
enum AuthType {
phone, email, sms, password
}
enum_only_string(AuthType);
Если вы хотите поддерживать устаревший код / хранилище данных, вы можете сохранить цифровые клавиши.
таким образом, вы можете избежать ввода значений дважды.
очень, очень, очень простое перечисление со строкой (TypeScript 2.4)
import * from '../mylib'
export enum MESSAGES {
ERROR_CHART_UNKNOWN,
ERROR_2
}
export class Messages {
public static get(id : MESSAGES){
let message = ""
switch (id) {
case MESSAGES.ERROR_CHART_UNKNOWN :
message = "The chart does not exist."
break;
case MESSAGES.ERROR_2 :
message = "example."
break;
}
return message
}
}
function log(messageName:MESSAGES){
console.log(Messages.get(messageName))
}
Я пробовал в TypeScript 1.5, как показано ниже, и это сработало для меня
module App.Constants {
export enum e{
Hello= ("Hello") as any,
World= ("World") as any
}
}
Я искал способ реализовать описания в перечислениях typescript (v2.5) и эта картина работала для меня:
export enum PriceTypes {
Undefined = 0,
UndefinedDescription = 'Undefined' as any,
UserEntered = 1,
UserEnteredDescription = 'User Entered' as any,
GeneratedFromTrade = 2,
GeneratedFromTradeDescription = 'Generated From Trade' as any,
GeneratedFromFreeze = 3,
GeneratedFromFreezeDescription = 'Generated Rom Freeze' as any
}
...
GetDescription(e: any, id: number): string {
return e[e[id].toString() + "Description"];
}
getPriceTypeDescription(price: IPricePoint): string {
return this.GetDescription(PriceTypes, price.priceType);
}