Search code examples
typescriptservicestack

ServiceStack - how to add custom typescript decorators?


I'm generating typescript dtos via C# models under ServiceStack.

I'm hoping to use typestack/class-validator which operates by evaluating several decorators that it provides.

Is there a way in ServiceStack's typescript generation for including arbitrary decorators beyond the usual DataAnnotations attributes on the C# side or must I create new C# attributes to mirror what I want to show up on the typescript side?


Solution

  • Edit:

    As your solution is more UX-friendly I've also decided to implement this feature where you can instead use [Emit{Language}] attributes to generate code before each type or property, e.g:

    [EmitTypeScript("@Validate()")]
    public class User
    {
        [EmitTypeScript("@IsNotEmpty()", "@IsEmail()")]
        public string Email { get; set; }
    }
    

    You can also use [EmitCode] to emit code for multiple languages, e.g. this adds annotations to both Dart & TypeScript.

    [EmitCode(Lang.Dart | Lang.TypeScript, "@Validate()")]
    public class User
    {
        [EmitCode(Lang.Dart | Lang.TypeScript, new[]{ "@IsNotEmpty()", "@IsEmail()" })]
        public string Email { get; set; }
    }
    

    In addition you can use the PreTypeFilter, InnerTypeFilter & PostTypeFilter to generate source code before and after a Type definition, e.g. this will append the @validate() annotation on non enum types:

    TypeScriptGenerator.PreTypeFilter = (sb, type) => {
        if (!type.IsEnum.GetValueOrDefault())
        {
            sb.AppendLine("@Validate()");
        }
    };
    

    The InnerTypeFilter gets invoked just after the Type Definition which can be used to generate common members for all Types and interfaces, e.g:

    TypeScriptGenerator.InnerTypeFilter = (sb, type) => {
        sb.AppendLine("id:string = `${Math.random()}`.substring(2);");
    };
    

    They previously didn't exist but I've also just added PrePropertyFilter & PostPropertyFilter for generating source before and after properties, e.g:

    TypeScriptGenerator.PrePropertyFilter = (sb , prop, type) => {
        if (prop.Name == "Id")
        {
            sb.AppendLine("@IsInt()");
        }
    };
    

    Pre/Post PropertyFilter's are available from v5.9.3+ that's now available on MyGet.