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.svgTo 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;
}