Автоматическое перечисление строк - PullRequest
0 голосов
/ 08 июня 2018

Строковое перечисление, подобное следующему, выглядит довольно избыточным, утомительным для кода и склонным к ошибкам, если вы неправильно набираете код при создании дубликата (см. Как в последнем примере)

enum Cmd{
    StartServer = "StartServer",
    StopServer = "StopServer",
    ResumServer1 = "ResumeServer1",
    ResumServer2 = "ResumeServer1"   // this would cause problems
}

Яищу способ объявить только элементы перечисления и сделать так, чтобы значения автоматически соответствовали имени символа и опционально с префиксом

. Дальше я прибыл к чему-то вроде этого:

export function stringifyEnum(enu:any, prefix:string=undefined){   

  Object.keys(enu).forEach( k =>{
    if (isNumber(k))
        enu[k] = prefix+enu[k]
    else
        enu[k] = prefix+k
  })
}

это похоже на работу:

enum Cmd{
    StartServer,
    StopServer,
    ResumeServer1,
    ResumeServer2
}

stringifyEnum(Cmd,"Cmd")
console.log(Cmd.StartServer)  // --> CmdStartServer

При таком подходе пока единственная проблема состоит в том, что машинописный текст считает, что перечисление является числовым, и в некоторых случаях жалуется.

Есть ли лучший подход к этому (главная цель здесь - краткое перечисление) или вы видите скрытые риски в этой идее?

Ответы [ 3 ]

0 голосов
/ 08 июня 2018

Если вы ищете способ реализовать сценарий, в котором несколько ключей могут отображаться на одно и то же значение, карта может помочь вам в этом.Вы можете заморозить его, чтобы убедиться, что он неизменен:

const CmdMap = {
    StartServer: "StartServer",
    StopServer: "StopServer",
    ResumServer1: "ResumeServer1",
    ResumServer2: "ResumeServer1"
};

Object.freeze(CmdMap);

Если вы хотите иметь префиксные команды, получите карту с завода:

function getCommandMap(prefix: string) {
    const cmdMap = {
        StartServer: `${prefix}StartServer`,
        StopServer: `${prefix}StopServer`,
        ResumServer1: `${prefix}ResumeServer1`,
        ResumServer2: `${prefix}ResumeServer1`
    };

    Object.freeze(cmdMap);

    return cmdMap;
}

const CmdMap = getCommandMap('Cmd');

console.log(CmdMap.StartServer);
0 голосов
/ 08 июня 2018

Я не думаю, что вы можете программно сделать префикс, чтобы система типов понимала его;для этого потребуются некоторые операции type , которые еще не являются частью языка.Существует существующее предложение для этой функции, но похоже, что никто не работает над ней.


Что касается получения ключа и значения, которые должны быть точно такими жеВы можете написать функцию, которая берет список строк и создает карту типа enum со строгой типизацией:

function enumize<K extends string>(...args: K[]): {[P in K]: P} {
  const ret = {} as {[P in K]: P};
  args.forEach(k => ret[k]=k);
  return ret;
}
const Cmd = enumize("StartServer", "StopServer", "ResumeServer1", "ResumeServer2");

Признается, что значение Cmd имеет тип { StartServer: "StartServer"; ... }.Вы сможете получить доступ к элементам, как и ожидалось:

console.log(Cmd.StartServer); // works

Официальный enum также создает несколько именованных типов , которых enumize() нет.Чтобы полностью воспроизвести типы, вам нужно проделать дополнительную работу:

type Cmd = keyof typeof Cmd; // allows you to refer to the type Cmd as before

Это тип объединения, упомянутый в ответе @ RobbyCornelissen.Вам это нужно, если вы собираетесь ссылаться на Cmd как на тип, например:

declare function requireCmd(cmd: Cmd); // the Cmd here is a type
requireCmd(Cmd.StopServer); // works

Если вам нужно сослаться на типы каждого элемента enum, вам придется выполнять еще большую работувключая уродливое дублирование кода:

namespace Cmd {
  export type StartServer = typeof Cmd.StartServer
  export type StopServer = typeof Cmd.StopServer
  export type ResumeServer1 = typeof Cmd.ResumeServer1
  export type ResumeServer2 = typeof Cmd.ResumeServer2
}

Этот материал понадобится для ссылки на такие типы, как Cmd.StopServer, например:

interface CommandInfo {
  kind: Cmd;
}

interface StopServerInfo extends CommandInfo {
   kind: Cmd.StopServer;  // need namespace for this line
   commandIssueDate: Date;
   numberOfUsersForcedOffline: number;
}

Но если вы не собираетесь этого делатьочень много, тогда вы можете пропустить namespace материал ... вы всегда можете использовать тип typeof Cmd.StopServer вместо этого.


Надеюсь, это поможет;удачи.


0 голосов
/ 08 июня 2018

У меня есть почти все заброшенные перечисления в TypeScript в пользу строковых литералов типов объединения .

Для вашего примера это будет выглядеть так:

type Cmd = 'StartServer' | 'StopServer' | 'ResumeServer1' | 'ResumeServer2';

Этот подходдаст вам те же преимущества при проверке во время компиляции, что и перечисление:

function foo(cmd: Cmd) {}

foo('StartServer'); // OK
foo('BeginServer'); // error
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...