Generate Typescript From Enum
20 May 2016
Hello everybody,
today I want to share with the world code, which generates typescript from enum declaration. I suppose everything should be understandable from code itself:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace System { public static class AttributesSimplification { /* [Description("Enumerations")] public enum EnumSample { [Description("Choice One")] ChoiceOne, [Description("Choice Two")] ChoiceTwo, } gives following ts: module Enumerations { export module EnumSample { export enum Enum { ChoiceOne = 0, ChoiceTwo = 2 } export function describe (enumValue: Enum) { switch (enumValue) { case Enum.ChoiceOne: return "Choice One"; case Enum.ChoiceTwo: return "Choice Two"; default: throw Error("Unknown Enum Value"); } } } } export = Enumerations; */ // Since Enum Type implements IConvertible interface we can pass into method enum //http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum public static string GetTypeScriptRepresentation<T>() where T :struct , IConvertible { if (!typeof(T).IsEnum) { throw new ArgumentException("T must be an enumerated type"); } StringBuilder sb = new StringBuilder(); var defaultInstance = new T(); var values = Enum.GetValues(typeof(T)).Cast<T>().ToList(); var descAttribute = (DescriptionAttribute) Attribute.GetCustomAttribute(defaultInstance.GetType(), typeof(DescriptionAttribute)); string moduleName = string.Empty; if (descAttribute == null || string.IsNullOrEmpty(descAttribute.Description)) { moduleName = defaultInstance.GetType().Namespace; } else { moduleName = descAttribute.Description; } var enumName = defaultInstance.GetType().Name; string openingBr = "{"; string closingBr = "}"; sb.Append($"module {moduleName} \r\n {openingBr} \r\n"); sb.Append($"\texport module {enumName} \r\n\t {openingBr} \r\n"); sb.Append($"\t\texport enum Enum \r\n\t\t{openingBr}"); var lastValue = values[values.Count - 1]; foreach (var value in values) { var intPresentation = Convert.ToInt32(value as System.Enum); sb.Append($"\r\n\t\t\t\t{value.ToString()} = {intPresentation.ToString()}" ); if (value.ToString() != lastValue.ToString()) { sb.Append(","); } else { sb.Append("\r\n"); } } sb.Append($"\t\t{closingBr}"); sb.Append("\r\n\texport function describe (enumValue: Enum) \r\n\t{"); sb.Append("\r\n\t\tswitch (enumValue) \r\n\t\t{\r\n"); foreach (var value in values) { sb.Append("\t\t\t\tcase Enum."); sb.Append(value.ToString()); sb.Append(":"); sb.Append("\r\n\t\t\t\t\t return \"" + GetDescription(value as System.Enum) + "\""); sb.Append(";\r\n"); } sb.Append("\t\t\tdefault:\r\n"); sb.Append("\t\t\t\tthrow Error(\"Unknown Enum Value\");"); sb.Append("\r\n\t\t\t}\r\n\t\t }\r\n\t}\r\n}\r\n"); return sb.ToString(); } public static void WriteFile(string filePath, string content) { if (System.IO.File.Exists(filePath)) { IO.File.Delete(filePath); } System.IO.File.WriteAllText(filePath, content); } public static string GetDescription(this Enum value) { DescriptionAttribute attribute = value.GetType() .GetField(value.ToString()) .GetCustomAttributes(typeof(DescriptionAttribute), false) .SingleOrDefault() as DescriptionAttribute; return attribute == null ? value.ToString() : attribute.Description; } public static T GetEnumValueFromDescription<T>(string description) { var type = typeof(T); if (!type.IsEnum) throw new ArgumentException(); var fields = type.GetFields(); var field = fields .SelectMany(f => f.GetCustomAttributes( typeof(DescriptionAttribute), false), ( f, a) => new { Field = f, Att = a }).SingleOrDefault(a => ((DescriptionAttribute)a.Att) .Description == description); return field == null ? default(T) : (T)field.Field.GetRawConstantValue(); } } }
Some examples of it's job:
AttributesSimplification.GetTypeScriptRepresentation<System.UriHostNameType>()
As result gives the following:
declare module System { interface Uri { AbsolutePath: string; AbsoluteUri: string; Authority: string; DnsSafeHost: string; Fragment: string; Host: string; HostNameType: System.UriHostNameType.Enum; IdnHost: string; IsAbsoluteUri: boolean; IsDefaultPort: boolean; IsFile: boolean; IsLoopback: boolean; IsUnc: boolean; LocalPath: string; OriginalString: string; PathAndQuery: string; Port: number; Query: string; Scheme: string; Segments: string[]; UserEscaped: boolean; UserInfo: string; } }
If you'll have the following declaration:
[Description("DomainModels.Location")] public enum LocationLevel { //Country - ProvincePart levels do not use as they are in nuts codes but can be added if necesary Country = 1, CountryPart = 2, Province = 3, ProvincePart = 4, Municipality = 5, City = 6, }
Then with following code
AttributesSimplification.GetTypeScriptRepresentation<QCore.Portal.Models.DomainModels.Location.LocationLevel>()
you'll see the following TypeScript generated:
module DomainModels.Location { export module LocationLevel { export enum Enum { Country = 1, CountryPart = 2, Province = 3, ProvincePart = 4, Municipality = 5, City = 6 } export function describe (enumValue: Enum) { switch (enumValue) { case Enum.Country: return "Country"; case Enum.CountryPart: return "CountryPart"; case Enum.Province: return "Province"; case Enum.ProvincePart: return "ProvincePart"; case Enum.Municipality: return "Municipality"; case Enum.City: return "City"; default: throw Error("Unknown Enum Value"); } } } }
Take note, how attribute Description was applied.
One more example:
[Description("Models.DomainModels")] public enum AwardStatus { [Description("Still in progress")] StillInProgress, [Description("Awarded")] Awarded, [Description("Withdrawn")] Withdrawn }
AttributesSimplification.GetTypeScriptRepresentation<DomainModels.AwardStatus>()
gives following TS:
module Models.DomainModels { export module AwardStatus { export enum Enum { StillInProgress = 0, Awarded = 1, Withdrawn = 2 } export function describe (enumValue: Enum) { switch (enumValue) { case Enum.StillInProgress: return "Still in progress"; case Enum.Awarded: return "Awarded"; case Enum.Withdrawn: return "Withdrawn"; default: throw Error("Unknown Enum Value"); } } } }
So, if you need some kind of enums generation, you can use my utility.
If you found this utility for generating TypeScript from enum declarations helpful and are looking to streamline your Acumatica development process, why not take it a step further? Customizations can make your Acumatica experience even more powerful and tailored to your unique business needs.
Leave a customization request today and let’s work together to build solutions that elevate your Acumatica implementation. Whether it’s enhancing enums, optimizing workflows, or creating entirely new features, we’re here to help you achieve your goals.