Converters

Language Converters

typeDiagram includes bidirectional converters for TypeScript, Python, Rust, Go, C#, F#, Dart, PHP, and Protobuf. Each converter can parse existing type definitions into a typeDiagram model, and emit type definitions from a model. All nine converters losslessly round-trip the canonical home-page sample (TD → lang → TD is byte-for-byte identical).

How it works

TypeScript source  ──→  Model  ──→  SVG diagram
                          ↕
Python source      ←──  Model  ←──  typeDiagram source
 

Converters target the Model layer (Layer 2 of the framework). They don't round-trip through DSL text — they work directly with the resolved type graph.

TypeScript

What maps

TypeScript typeDiagram
interface User { ... } type User { ... }
type Shape = Circle | Square union Shape { Circle, Square }
type Email = string alias Email = String
string String
number Int
boolean Bool
Array<T> List<T>
Map<K,V> Map<K,V>

From TypeScript

// Input
export interface User {
  id: string;
  name: string;
  email: string | undefined;
}
typediagram --from typescript types.ts > diagram.svg

To TypeScript

Emits export interface for records, discriminated unions with a kind field for unions, export type X = Y for aliases.

Python

What maps

Python typeDiagram
@dataclass class User type User { ... }
class Color(str, Enum) union Color { ... }
class Config(TypedDict) type Config { ... }
str String
int Int
float Float
bool Bool
list[T] / List[T] List<T>
dict[K,V] / Dict[K,V] Map<K,V>
Optional[T] Option<T>

To Python

Emits @dataclass for records, str, Enum for unions with no payloads, separate dataclass per variant + type alias for unions with payloads.

Rust

What maps

Rust typeDiagram
pub struct User { ... } type User { ... }
pub enum Shape { ... } union Shape { ... }
pub type Email = String alias Email = String
String / &str String
i32 / i64 / u64 Int
f64 Float
bool Bool
Vec<T> List<T>
HashMap<K,V> Map<K,V>
Option<T> Option<T>

Supports struct variants, tuple variants, and unit variants in enums. Generic bounds (e.g. T: Clone) are parsed but bounds are dropped (only the type parameter name is kept).

Go

What maps

Go typeDiagram
type User struct { ... } type User { ... }
type Shape interface { ... } union Shape { ... }
type Email = string alias Email = String
string String
int64 Int
float64 Float
bool Bool
[]T List<T>
map[K]V Map<K,V>
*T Option<T>

Go doesn't have native sum types. Interfaces are mapped to unions; exported field names are lowercased in the typeDiagram output.

C#

What maps

C# typeDiagram
record User(...) type User { ... }
abstract record + nested sealed record union Shape { ... }
enum Color { ... } union Color { ... }
using Email = string; alias Email = String

Tagged unions emit as a closed hierarchy (abstract record + nested sealed records, RestClient.Net / Outcome style). Primary-constructor records preserve the original field names. Aliases emit as using Email = string;.

F#

What maps

F# typeDiagram
type User = { ... } type User { ... }
type Shape = Circle | Square union Shape { ... }
type Email = string alias Email = String

F# discriminated unions map directly. Record syntax is used for struct types.

Dart

What maps

Dart typeDiagram
final class User { ... } type User { ... }
sealed class Shape + extends/implements variants union Shape { ... }
typedef Email = String alias Email = String
T? Option<T>
List<T> List<T>
Map<K,V> Map<K,V>

Uses Dart 3 sealed class for tagged unions. First-class generics are preserved.

PHP

What maps

PHP typeDiagram
final readonly class User { ... } type User { ... }
sealed interface + implementing classes union Shape { ... }
@typediagram-kind alias docblock alias Email = String
?string Option<String>
@param list<T> List<T>
@param array<K,V> Map<K,V>

Emits final readonly class DTOs with constructor-promoted public params, declare(strict_types=1), and PHPStan docblocks for generics. Tagged unions use a sealed interface with implementing classes and @var 'Kind' tags. Note: Option<Unit> is not round-trippable because both collapse to PHP null on parse.

Protobuf

What maps

Protobuf typeDiagram
message User { ... } type User { ... }
enum Color { ... } union Color { Red, Green, Blue }
oneof + nested message variants union Shape { ... }
optional T Option<T>
repeated T List<T>
map<K,V> Map<K,V>

Uses proto3 syntax. Because proto3 can't natively express generics, Option<List<T>>, or type aliases, the converter encodes these via comment directives: // @td-generics:, // @td-type:, // @td-alias:. Unit-only unions emit as enum; struct-variant unions emit as oneof with nested message types.

Programmatic API

import { converters } from "typediagram-core";

// Parse TypeScript source into a Model
const result = converters.typescript.fromSource(tsCode);
if (result.ok) {
  const model = result.value;

  // Convert to Rust
  const rustCode = converters.rust.toSource(model);

  // Convert to Python
  const pyCode = converters.python.toSource(model);

  // Render to SVG (via typeDiagram DSL)
  const { model: modelLayer } = await import("typediagram");
  const tdSource = modelLayer.printSource(model);
  const svg = await renderToString(tdSource);
}

// Available converters
converters.typescript;
converters.python;
converters.rust;
converters.go;
converters.csharp;
converters.fsharp;
converters.dart;
converters.php;
converters.protobuf;

Each converter implements the Converter interface:

interface Converter {
  readonly language: Language;
  fromSource(source: string): Result<Model, Diagnostic[]>;
  toSource(model: Model): string;
}