Skip to main content
The Intent.Modules.Common.TypeScript module provides comprehensive support for generating TypeScript and JavaScript code, with support for modern ES6+ features, module systems, and NPM package management.

Template Base Class

All TypeScript templates inherit from TypeScriptTemplateBase<TModel>, which provides:
  • Automatic import management: ES6 imports with named and default exports
  • NPM dependency management: Register package dependencies for package.json
  • Type resolution: Resolves types from other templates with relative paths
  • Module path calculation: Automatically computes relative import paths

Basic Template Structure

public class MyTypeScriptTemplate : TypeScriptTemplateBase<ClassModel>
{
    public const string TemplateId = "MyCompany.MyTypeScriptTemplate";

    public MyTypeScriptTemplate(IOutputTarget outputTarget, ClassModel model) 
        : base(TemplateId, outputTarget, model)
    {
        // Configure type sources
        AddTypeSource("OtherTypeScriptTemplate.TemplateId");
    }

    public override ITemplateFileConfig GetTemplateFileConfig()
    {
        return new TypeScriptFileConfig(
            className: Model.Name,
            @namespace: null, // TypeScript uses file-based modules
            relativeLocation: "models");
    }

    public override string TransformText()
    {
        return $@"
import {{ Observable }} from 'rxjs';

export class {ClassName} {{
    // Generated code
}}";
    }
}

Key Properties and Methods

// Access the configured class name
public string ClassName { get; }

// TypeScript uses file-based modules, not namespaces
public string Namespace { get; } // Usually null or used for organization

TypeScript Code Builder (TypescriptFile)

The TypescriptFile builder provides a fluent API for constructing TypeScript code:
public class MyTypeScriptBuilderTemplate : TypeScriptTemplateBase<ClassModel>, ITypescriptFileBuilderTemplate
{
    public TypescriptFile TypescriptFile { get; }

    public MyTypeScriptBuilderTemplate(IOutputTarget outputTarget, ClassModel model)
        : base(TemplateId, outputTarget, model)
    {
        TypescriptFile = new TypescriptFile(this.GetFolderPath(), this)
            .AddClass(model.Name, @class =>
            {
                @class
                    .Export()
                    .ExtendsClass("BaseEntity")
                    .ImplementsInterface("IEntity")
                    .AddConstructor(ctor =>
                    {
                        ctor
                            .AddParameter("id", "string")
                            .AddStatement("this.id = id;");
                    })
                    .AddProperty("name", "string", prop => 
                    {
                        prop.WithAccessor(AccessorType.Public);
                    })
                    .AddMethod("getName", method =>
                    {
                        method
                            .WithReturnType("string")
                            .AddStatement("return this.name;");
                    });
            });
    }

    public override ITemplateFileConfig GetTemplateFileConfig() 
        => TypescriptFile.GetConfig(Model.Name);

    public override string TransformText() => TypescriptFile.ToString();
}

Building Classes

TypescriptFile.AddClass("User", @class =>
{
    @class
        .Export() // Creates "export class User"
        .ExtendsClass("BaseEntity")
        .ImplementsInterface("IUser")
        .ImplementsInterfaces(new[] { "ISerializable", "IValidatable" })
        .AddGenericParameter("T")
        .Abstract();
});

Interfaces

TypescriptFile.AddInterface("IUserRepository", @interface =>
{
    @interface
        .Export()
        .ExtendsInterface("IRepository<User>")
        .AddProperty("findByName", prop =>
        {
            prop.WithType("(name: string) => Promise<User[]>");
        })
        .AddMethod("findByEmail", method =>
        {
            method
                .WithReturnType("Promise<User | null>")
                .AddParameter("email", "string");
        });
});

Type Aliases and Enums

TypescriptFile.AddVariable("UserId", variable =>
{
    variable
        .WithType("string")
        .Export()
        .AsType(); // Creates: export type UserId = string;
});

TypescriptFile.AddVariable("UserOrAdmin", variable =>
{
    variable
        .WithType("User | Admin")
        .Export()
        .AsType();
});

Import Statements

TypeScript’s import system is flexible and powerful:
// Single named import
TypescriptFile.AddImport("Component", "@angular/core");
// import { Component } from '@angular/core';

// Multiple named imports
TypescriptFile.AddImports(new[] { "Component", "OnInit" }, "@angular/core");
// import { Component, OnInit } from '@angular/core';

// Import with alias
TypescriptFile.AddImport("Component", "Comp", "@angular/core");
// import { Component as Comp } from '@angular/core';

Modern TypeScript Features

Decorators

// Class decorators
@class.AddDecorator("@Component", decorator =>
{
    decorator.AddArgument(@"
    {
        selector: 'app-user',
        templateUrl: './user.component.html'
    }
    ");
});

// Property decorators
property.AddDecorator("@Input()");
property.AddDecorator("@Output()");

// Method decorators
method.AddDecorator("@Get", decorator =>
{
    decorator.AddArgument("'/users/:id'");
});

// Parameter decorators
parameter.AddDecorator("@Param", decorator =>
{
    decorator.AddArgument("'id'");
});

Generics

@class
    .AddGenericParameter("T")
    .AddGenericParameter("K extends keyof T");

method
    .WithReturnType("T[K]")
    .AddParameter("obj", "T")
    .AddParameter("key", "K")
    .AddStatement("return obj[key];");

// Generic constraints
@interface
    .AddGenericParameter("T extends BaseModel")
    .AddMethod("save", method =>
    {
        method
            .WithReturnType("Promise<T>")
            .AddParameter("entity", "T");
    });

Advanced Types

// Mapped types
TypescriptFile.AddVariable("Readonly", variable =>
{
    variable
        .WithType("<T>() => { readonly [P in keyof T]: T[P] }")
        .Export()
        .AsType();
});

// Conditional types
TypescriptFile.AddVariable("NonNullable", variable =>
{
    variable
        .WithType("<T>() => T extends null | undefined ? never : T")
        .Export()
        .AsType();
});

// Utility types
var partialUser = "Partial<User>";
var readonlyUser = "Readonly<User>";
var pickUser = "Pick<User, 'id' | 'name'>";
var omitUser = "Omit<User, 'password'>";

Framework-Specific Features

@class
    .AddDecorator("@Component", d => d.AddArgument(@"
        {
            selector: 'app-user-list',
            templateUrl: './user-list.component.html',
            styleUrls: ['./user-list.component.css']
        }
    "))
    .ImplementsInterface("OnInit")
    .AddMethod("ngOnInit", method =>
    {
        method.AddStatement("this.loadUsers();");
    });

NPM Package Management

Intent can automatically manage your package.json dependencies:
// In your template constructor
AddDependency(new NpmPackageDependency(
    name: "express",
    version: "^4.18.0"));

AddDependency(new NpmPackageDependency(
    name: "typescript",
    version: "^5.0.0",
    isDev: true));

AddDependency(new NpmPackageDependency(
    name: "@types/node",
    version: "^18.0.0",
    isDev: true));

File Configuration

return new TypeScriptFileConfig(
    className: "UserService",
    @namespace: null, // TypeScript doesn't use namespaces like C#
    relativeLocation: "services");

// Results in: src/services/user-service.ts

Best Practices

Generate code that works with strict: true in tsconfig.json:
  • Use explicit types everywhere
  • Handle null and undefined properly
  • Use readonly where appropriate
  • Use PascalCase for classes and interfaces (User, IUserRepository)
  • Use camelCase for properties and methods (firstName, getUserById)
  • Prefer interfaces over type aliases for object shapes
  • Use enum for discrete values
  • One class/interface per file (with rare exceptions)
  • Use index.ts to create public APIs
  • Keep related types together (User, UserDto, IUserRepository)
Use the GetRelativePath() method for imports between generated files. This ensures correct relative paths regardless of folder structure.

Comparing with C# and Java

FeatureTypeScriptC#Java
Module SystemES6 imports/exportsNamespace + usingPackage + import
Type SystemStructural typingNominal typingNominal typing
Nullabilitystring | null or string?string? (C# 8+)@Nullable (annotations)
PropertiesClass fields or gettersProperties with get/setGetter/setter methods
Package Managernpm/yarnNuGetMaven/Gradle

See Also

C# Support

Generate C# code for .NET projects

Java Support

Generate Java code for JVM projects

Template Basics

Learn about Intent templates

Type Resolution

Understanding cross-template type references