ts_generator ~main

Automatic TypeScript interface and enum code generator from D types compatible with vibe.d.


To use this package, run the following command in your project's root directory:

Manual usage
Put the following dependency into your project's dependences section:


This package provides sub packages which can be used individually:

ts_generator:example - Example application demonstrating ts_generator usage

ts_generator:example_vibe - Example application demonstrating vibe.d REST API interface and Fetch client generation

ts_generator

A lightweight, zero-dependency D library for automatically generating TypeScript interface, enum, and REST API Client (fetch) code from D struct, class, enum, and interface types using compile-time reflection (__traits and CTFE). This library is compatible with vibe.d.

DUB Package License: MIT

Features

  • Compile-Time Generation: Generates TypeScript code entirely at compile time using D traits and CTFE.
  • vibe.d Serialization UDAs Compatible:
  • @name("custom_name"): Custom field name mapping in TypeScript interfaces.
  • @optional: Renders optional fields (field?: type).
  • @ignore: Excludes private / internal fields from generated TypeScript code.
  • @byName: Enum serialization by string member name.
  • REST API Client Generator (`generateTypeScriptApiClient`):
  • Automatically inspects D REST interfaces (vibe.web.rest compatible).
  • Infers HTTP verbs (GET, POST, PUT, PATCH, DELETE) and @path("/api/v1/resource/:id") endpoints.
  • Generates strongly-typed asynchronous TypeScript API Client classes using native fetch.
  • Recursive Type Discovery: Automatically finds and emits all nested structs, classes, and enums referenced in your fields, return types, or parameters.
  • Nullable & Datetime Support: Supports std.typecons.Nullable!T (T | null) and std.datetime types (SysTime, DateTime, Date -> string).

Installation

Add ts_generator to your dub.json:

"dependencies": {
    "ts_generator": "~>1.0.0"
}

Or run:

dub add ts_generator

Usage Examples

1. Generating TypeScript Models

import std.file : write, mkdirRecurse;
import ts_generator;

struct optional {}
struct ignore {}
struct name { string value; }

struct UserProfile {
    @name("user_id") int id;
    string username;
    @optional string bio;
    @ignore string internalSecurityToken;
}

void main()
{
    string ts = generateTypeScript!(UserProfile)();
    mkdirRecurse("frontend/src/types");
    write("frontend/src/types/api.d.ts", ts);
}

Output (`frontend/src/types/api.d.ts`):

export interface UserProfile {
    user_id: number;
    username: string;
    bio?: string;
}

2. Generating a Full REST API Fetch Client (vibe.web.rest compatible)

import std.file : write, mkdirRecurse;
import ts_generator;

struct path { string value; }
struct optional {}

struct UserProfile {
    int id;
    string username;
    @optional string bio;
}

struct CreateUserDto {
    string username;
    @optional string bio;
}

interface UserApi {
    @path("/api/v1/users")
    UserProfile[] getUsers();

    @path("/api/v1/users/:id")
    UserProfile getUser(int id);

    @path("/api/v1/users")
    UserProfile createUser(CreateUserDto dto);

    @path("/api/v1/users/:id")
    void deleteUser(int id);
}

void main()
{
    // Generates both data models AND the TypeScript API client class
    string code = generateTypeScriptApiClient!(UserApi)();
    
    mkdirRecurse("frontend/src/api");
    write("frontend/src/api/client.ts", code);
}

Output (`frontend/src/api/client.ts`):

export interface UserProfile {
    id: number;
    username: string;
    bio?: string;
}

export interface CreateUserDto {
    username: string;
    bio?: string;
}

export class UserApiClient {
    private baseUrl: string;
    private fetchFn: typeof fetch;

    constructor(baseUrl: string = '', fetchFn: typeof fetch = fetch) {
        this.baseUrl = baseUrl;
        this.fetchFn = fetchFn;
    }

    async getUsers(): Promise<UserProfile[]> {
        const response = await this.fetchFn(`${this.baseUrl}/api/v1/users`, {
            method: 'GET',
            headers: { 'Accept': 'application/json' }
        });
        if (!response.ok) throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
        return await response.json();
    }

    async getUser(id: number): Promise<UserProfile> {
        const response = await this.fetchFn(`${this.baseUrl}/api/v1/users/${id}`, {
            method: 'GET',
            headers: { 'Accept': 'application/json' }
        });
        if (!response.ok) throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
        return await response.json();
    }

    async createUser(dto: CreateUserDto): Promise<UserProfile> {
        const response = await this.fetchFn(`${this.baseUrl}/api/v1/users`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
            body: JSON.stringify(dto)
        });
        if (!response.ok) throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
        return await response.json();
    }

    async deleteUser(id: number): Promise<void> {
        const response = await this.fetchFn(`${this.baseUrl}/api/v1/users/${id}`, {
            method: 'DELETE',
            headers: { 'Accept': 'application/json' }
        });
        if (!response.ok) throw new Error(`HTTP error ${response.status}: ${response.statusText}`);
    }
}

Running Tests & Examples

To run unit tests:

dub test

To run the basic example:

dub run :example

To run the vibe.d REST Client example:

dub run :example_vibe

License

MIT © Pablo De Nápoli

Authors:
  • Pablo De Nápoli
Sub packages:
ts_generator:example, ts_generator:example_vibe
Dependencies:
none
Versions:
0.2.0 2026-Sep-01
0.1.0 2026-Sep-01
~main 2026-Sep-01
Show all 3 versions
Download Stats:
  • 1 downloads today

  • 1 downloads this week

  • 1 downloads this month

  • 1 downloads total

Score:
0.0
Short URL:
ts_generator.dub.pm