# tauri-ts-generator
CLI tool to automatically generate TypeScript bindings from Tauri commands.
## Description
`tauri-ts-generator` scans your Rust code, finds all functions with the `#[tauri::command]` macro, and automatically generates:
- **TypeScript interfaces** for Rust structs and enums
- **TypeScript wrapper functions** to invoke Tauri commands via `invoke()`
This ensures type-safe interaction between the TypeScript frontend and Rust backend, minimizing manual boilerplate.
## Installation
```bash
cargo install --path .
```
Or build from source:
```bash
cargo build --release
```
## Quick Start
### 1. Initialize Configuration
```bash
cd your-tauri-project
tauri-ts-generator init
```
This will create a `tauri-codegen.toml` file with default settings.
### 2. Configure Settings
Edit `tauri-codegen.toml`:
```toml
[input]
source_dir = "src-tauri/src"
exclude = ["tests", "target"]
# Optional: enable for macro-generated types (requires cargo-expand)
# use_cargo_expand = true
# cargo_manifest = "src-tauri/Cargo.toml"
[output]
types_file = "src/generated/types.ts"
commands_file = "src/generated/commands.ts"
[naming]
type_prefix = ""
type_suffix = ""
function_prefix = ""
function_suffix = ""
```
### 3. Generate TypeScript Code
```bash
tauri-ts-generator generate
```
Or with verbose output:
```bash
tauri-ts-generator generate --verbose
```
## Example
### Rust Code (Input)
```rust
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct User {
pub id: i32,
pub name: String,
pub email: Option<String>,
}
#[derive(Serialize, Deserialize)]
pub enum UserStatus {
Active,
Inactive,
Pending,
}
#[tauri::command]
pub async fn get_user(id: i32) -> Result<User, String> {
// ...
}
#[tauri::command]
pub async fn get_all_users() -> Result<Vec<User>, String> {
// ...
}
#[tauri::command]
pub fn greet(name: String) -> String {
format!("Hello, {}!", name)
}
```
### TypeScript Code (Output)
**types.ts:**
```typescript
// This file was auto-generated by tauri-ts-generator
// Do not edit this file manually
export interface User {
id: number;
name: string;
**commands.ts:**
```typescript
// This file was auto-generated by tauri-ts-generator
// Do not edit this file manually
import { invoke } from "@tauri-apps/api/core";
import type { User } from "./types";
export async function getUser(id: number): Promise<User> {
return invoke<User>("get_user", { id });
}
export async function getAllUsers(): Promise<User[]> {
return invoke<User[]>("get_all_users");
}
export async function greet(name: string): Promise<string> {
return invoke<string>("greet", { name });
}
```
## Type Mapping
### Basic Types
| `String`, `&str`, `char` | `string` |
| `i8`, `i16`, `i32`, `i64`, `u8`, `u16`, `u32`, `u64` | `number` |
| `f32`, `f64` | `number` |
| `bool` | `boolean` |
| `Vec<T>` | `T[]` |
| `Option<T>` | `T \| null` |
| `Result<T, E>` | `Promise<T>` |
| `HashMap<K, V>` | `Record<K, V>` |
| `()` | `void` |
| Custom struct | TypeScript interface |
| Simple enum | String union type |
### External Types (Crates)
| `chrono::DateTime<Tz>` | `string` | ISO 8601 format |
| `chrono::NaiveDateTime` | `string` | ISO 8601 format |
| `chrono::NaiveDate` | `string` | YYYY-MM-DD |
| `chrono::NaiveTime` | `string` | HH:MM:SS |
| `time::OffsetDateTime` | `string` | ISO 8601 format |
| `time::PrimitiveDateTime` | `string` | ISO 8601 format |
| `uuid::Uuid` | `string` | UUID string |
| `rust_decimal::Decimal` | `string` | Numeric string |
| `std::path::PathBuf` | `string` | File path |
| `url::Url` | `string` | URL string |
| `std::net::IpAddr` | `string` | IP address |
| `std::time::Duration` | `number` | Seconds |
| `serde_json::Value` | `unknown` | Any JSON |
| `bytes::Bytes` | `number[]` | Byte array |
| Complex enum | Discriminated union |
## Configuration
### `[input]`
| `source_dir` | Directory with Rust source files | `src-tauri/src` |
| `exclude` | List of directories/files to exclude | `["tests", "target"]` |
| `use_cargo_expand` | Use cargo expand for macro-generated types | `false` |
| `cargo_manifest` | Path to Cargo.toml for cargo expand | auto-detected |
### `[output]`
| `types_file` | Path to generate TypeScript types | `src/generated/types.ts` |
| `commands_file` | Path to generate TypeScript commands | `src/generated/commands.ts` |
### `[naming]`
| `type_prefix` | Prefix for type names | `""` |
| `type_suffix` | Suffix for type names | `""` |
| `function_prefix` | Prefix for function names | `""` |
| `function_suffix` | Suffix for function names | `""` |
## CLI Commands
```bash
tauri-ts-generator <COMMAND>
Commands:
generate Generate TypeScript bindings
init Create configuration file
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
```
### generate
```bash
tauri-ts-generator generate [OPTIONS]
Options:
-c, --config <FILE> Path to config file [default: tauri-codegen.toml]
-v, --verbose Verbose output
-h, --help Print help
```
### init
```bash
tauri-ts-generator init [OPTIONS]
Options:
-o, --output <FILE> Path to create config file [default: tauri-codegen.toml]
-f, --force Overwrite existing file
-h, --help Print help
```
## Features
- **Automated Parsing** — uses `syn` to analyze Rust AST
- **Async Support** — correctly handles `async` commands
- **Custom Types** — parses structs and enums with `#[derive(Serialize)]` attributes
- **Serde Rename** — respects `#[serde(rename = "...")]`
- **Tauri Special Types** — automatically skips `State`, `Window`, `AppHandle`
- **Nested Modules** — scans commands inside `mod` blocks
- **Wildcard Re-exports** — supports `pub use module::*` patterns
- **Macro-generated Types** — optional support via `cargo expand`
## Macro-Generated Types
Some types in your project may be generated by macros (e.g., `progenitor`, `derive_builder`, etc.). These types don't exist as plain Rust source code, so the generator cannot find them by default.
### Detecting Unresolved Types
When the generator encounters types it cannot resolve, it will show a warning:
```
Warning: 4 type(s) could not be resolved and will not be generated:
- 'AuthTokens' (used in src/commands/auth.rs)
- 'UserProfile' (used in src/commands/auth.rs)
Hint: These types may be generated by macros (e.g., progenitor, serde, etc.).
To include macro-generated types, add to your config:
[input]
use_cargo_expand = true
```
### Using cargo expand
To include macro-generated types, enable `cargo expand` in your configuration:
```toml
[input]
source_dir = "src-tauri/src"
use_cargo_expand = true
cargo_manifest = "src-tauri/Cargo.toml" # optional, auto-detected
```
**Requirements:**
- Install cargo-expand: `cargo install cargo-expand`
- Nightly Rust toolchain (for cargo expand)
**Note:** Using `cargo expand` will compile your project, which may take longer than regular parsing.
## License
MIT