Skip to content

aarambh-darshan/typewriter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🖊️ typewriter

Cross-Language Type Synchronization SDK for Rust Define your types once in Rust. Get perfectly matching types in TypeScript, Python, Go, Swift, Kotlin, GraphQL, and JSON Schema — automatically, forever.

Crates.io Docs.rs License CI GitHub

🦀 Rust Core 🌐 Polyglot ⚡ Zero Drift 🔧 Proc Macro
proc macro powered 7+ languages forever in sync zero boilerplate

⚠️ The Problem

Every full-stack team using Rust on the backend faces the same invisible tax: keeping types in sync across languages.

Backend dev changes:                  Frontend/Mobile dev sees:
─────────────────────                 ─────────────────────────
pub struct User {                     interface User {
    pub id: Uuid,          ──────►      id: string;
    pub email: String,                  email: string;
    pub name: String,   ← ADDED        // ❌ missing: name
    pub role: Role,                     role: Role;
}                                     }
                                      // Runtime: undefined is not a string

OpenAPI codegen? Only works for HTTP APIs. Protobuf? Heavy toolchain. Manual sync? Humans forget.

Root cause: Every existing solution uses an intermediary format as source of truth instead of the Rust source itself.


✅ The Solution

typewriter makes your Rust structs and enums the single, permanent source of truth for all your type definitions.

Annotate once → generate everywhere. When the Rust type changes, every generated file updates automatically. No hand-maintained schema file. No intermediary format. No drift. Ever.

use typebridge::TypeWriter;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, TypeWriter)]
#[sync_to(typescript, python)]
pub struct UserProfile {
    pub id: Uuid,
    pub email: String,
    pub age: Option<u32>,
    pub role: UserRole,
    pub created_at: DateTime<Utc>,
}

// On cargo build, auto-generates:
// ✅ ./generated/typescript/user-profile.ts
// ✅ ./generated/typescript/user-profile.schema.ts
// ✅ ./generated/python/user_profile.py
// ✅ ./generated/go/user_profile.go
// ✅ ./generated/graphql/user_profile.graphql
// ✅ ./generated/json-schema/user_profile.schema.json

🚀 Quick Start

1. Add to Cargo.toml

[dependencies]
typebridge = "0.5.0"
serde = { version = "1", features = ["derive"] }

2. Annotate your types

use typebridge::TypeWriter;
use serde::{Serialize, Deserialize};

/// A user in the system.
#[derive(Serialize, Deserialize, TypeWriter)]
#[sync_to(typescript, python, go)]
pub struct User {
    pub id: String,
    pub email: String,
    pub name: String,
    pub age: Option<u32>,
    pub is_active: bool,
    pub tags: Vec<String>,
}

3. Build

cargo build

That's it. Check ./generated/typescript/, ./generated/python/, and ./generated/go/ for your generated files.


📦 Generated Output

TypeScript → user.ts

// Auto-generated by typewriter v0.4.2. DO NOT EDIT.

/**
 * A user in the system.
 */
export interface User {
  id: string;
  email: string;
  name: string;
  age?: number | undefined;
  is_active: boolean;
  tags: string[];
}

TypeScript Zod Schema → user.schema.ts

import { z } from 'zod';

export const UserSchema = z.object({
  "id": z.string(),
  "email": z.string(),
  "name": z.string(),
  "age": z.number().optional(),
  "is_active": z.boolean(),
  "tags": z.array(z.string()),
});

To consume generated schemas at runtime, install zod in your TS app. Set [typescript].zod = false to disable global schema output, and use #[tw(zod)]/#[tw(zod = false)] for per-type overrides:

npm install zod

Python → user.py

# Auto-generated by typewriter v0.4.2. DO NOT EDIT.

from pydantic import BaseModel
from typing import Optional

class User(BaseModel):
    """A user in the system."""
    id: str
    email: str
    name: str
    age: Optional[int] = None
    is_active: bool
    tags: list[str]

Go → user.go

// Code generated by typewriter v0.4.2. DO NOT EDIT.
// Source: User

package types

// A user in the system.
type User struct {
	Id        string  `json:"id"`
	Email     string  `json:"email"`
	Name      string  `json:"name"`
	Age       *uint32 `json:"age,omitempty"`
	Is_active bool    `json:"is_active"`
	Tags      []string `json:"tags"`
}

🎯 Features

✅ Core Generation Platform (v0.4.2)

  • TypeScript emitterexport interface, export type unions, optional fields
  • TypeScript Zod schemas — sibling <type>.schema.ts files with export const <Type>Schema = ... (enabled by default, configurable via [typescript].zod and #[tw(zod)]; runtime zod dependency)
  • Python emitter — Pydantic v2 BaseModel, Enum, Union with Literal discriminators
  • Go emitter — native struct parsing, interface data-carrying enums, and omitempty optional pointers
  • Swift emitterCodable structs and enums with CodingKeys
  • Kotlin emitterdata class and sealed class with kotlinx.serialization
  • GraphQL SDL emittertype, enum, union definitions with custom scalars (DateTime, JSON)
  • JSON Schema emitter — Draft 2020-12 object schemas, string enums, oneOf composition with format annotations (uuid, date-time, date)
  • Generic typesPagination<T>export interface Pagination<T> (TS) / class Pagination(BaseModel, Generic[T]) (Python)
  • Cross-file imports — auto import type { X } from './file' (TS) / from .file import X (Python)
  • Serde compatibility — auto-reads #[serde(rename, skip, tag, flatten)]
  • Custom attributes#[tw(skip)], #[tw(rename)], #[tw(optional)], #[tw(zod)]
  • Doc comments — Rust /// flows to JSDoc in TS, docstrings in Python, """ in GraphQL
  • Smart type unwrappingBox<T>, Arc<T>, Rc<T> transparently unwrapped
  • Feature-gated emitters — compile only what you need
  • TOML configtypewriter.toml for output directories, file naming styles, readonly mode

✅ Phase 3 CLI (v0.3.1)

  • typewriter generate <file> and typewriter generate --all
  • typewriter check --ci with drift detection gate
  • typewriter check --json / --json-out structured report output
  • typewriter watch [path] auto-regeneration on Rust file save
  • cargo typewriter ... subcommand support via cargo-typewriter
  • typebridge-cli package published as version 0.2.2.

See CLI Guide for full command reference and JSON schema.

🔮 Coming Soon

  • VSCode / Neovim extensions
  • Plugin API for custom language backends

See the full Roadmap for details.


⚙️ Configuration

Create a typewriter.toml at your project root (optional — sensible defaults are used):

[typescript]
output_dir = "../frontend/src/types"
file_style = "kebab-case"
readonly = false
zod = true

[python]
output_dir = "../api/schemas"
pydantic_v2 = true

[graphql]
output_dir = "../schema/types"
file_style = "snake_case"

[json_schema]
output_dir = "../schemas"
file_style = "snake_case"

See Configuration Guide for all options.


🏷️ Attributes

Serde Compatibility

typewriter automatically reads #[serde(...)] attributes — no need to repeat them:

#[derive(Serialize, Deserialize, TypeWriter)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum PaymentStatus {
    Pending,
    Completed { transaction_id: String },
    Failed { reason: String, code: u32 },
}

Custom Attributes

pub struct User {
    #[tw(skip)]                     // exclude from generated output
    pub password_hash: String,

    #[tw(rename = "displayName")]   // override field name
    pub username: String,

    #[tw(optional)]                 // force optional even if not Option<T>
    pub legacy_field: String,
}

See the full Attributes Guide.


📊 Type Mapping Reference

Rust Type TypeScript Python Go Swift Kotlin GraphQL JSON Schema
String string str string String String String string
u8u32, i8i32, f32, f64 number int / float uint* / int* / float* UInt* / Int* / Float/Double UInt / Int / Float/Double Int / Float integer / number
u64, i64 bigint int uint64 / int64 UInt64 / Int64 ULong / Long String integer
bool boolean bool bool Bool Boolean Boolean boolean
Option<T> T | undefined Optional[T] *T with omitempty T? T? = null nullable (no !) not in required
Vec<T> T[] list[T] []T [T] List<T> [T!] array
HashMap<K,V> Record<K, V> dict[K, V] map[K]V [K: V] Map<K, V> JSON object
Uuid string UUID string UUID String ID string + uuid format
DateTime<Utc> string datetime time.Time Date kotlinx.datetime.Instant DateTime string + date-time format

See full type mapping reference for all supported types.


🏗️ Architecture

typewriter is a Cargo workspace with focused, independently publishable crates:

typewriter/
├── typewriter-core/        ← IR types, TypeMapper trait, config
├── typewriter-engine/      ← Shared scan/parse/emit + drift orchestration
├── typewriter-macros/      ← #[derive(TypeWriter)] proc macro
├── typewriter-typescript/  ← TypeScript emitter
├── typewriter-python/      ← Python emitter
├── typewriter-go/          ← Go emitter
├── typewriter-swift/       ← Swift emitter
├── typewriter-kotlin/      ← Kotlin emitter
├── typewriter-graphql/     ← GraphQL SDL emitter
├── typewriter-json-schema/ ← JSON Schema emitter
├── typewriter-cli/         ← `typebridge-cli` package (`typewriter` + `cargo-typewriter` binaries)
├── typewriter/             ← Main user-facing crate (re-exports)
├── typewriter-test/        ← Snapshot tests
└── example/                ← Working usage examples

See ARCHITECTURE.md for the full technical deep-dive.


🤝 Contributing

We welcome contributions! See CONTRIBUTING.md for:

  • Development setup
  • Code style guidelines
  • How to add a new language emitter
  • PR and review process

📄 License

Apache License 2.0
Copyright 2026 Aarambh Dev Hub

See LICENSE for the full text.


Built with ❤️ and 🦀 by Aarambh Dev Hub

Define once. Generate everywhere. Never drift again.

⭐ Star this repo if you find it useful!

About

TypeBridge automatically generates TypeScript interfaces and Python Pydantic v2 models from your Rust structs and enums. Keep your frontend and backend types perfectly in sync with full Serde compatibility, native generic support, and auto-generated cross-file imports!

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages