Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
YouTube Security VideosWelcome to GitHub Copilot Day: the future of agentic engineering(22.09.2026 um 20:00 Uhr)
YouTube Security VideosMicrosoft Mechanics: What Can a Copilot Agent Actually Read?(22.09.2026 um 20:27 Uhr)
Unix & Linux ServerPeppermintOS Is Moving From Xorg to XLibre to Avoid Wayland(22.09.2026 um 19:58 Uhr)
Sicherheitslücken (CVE)USN-8803-1: Sudo vulnerability(22.09.2026 um 16:15 Uhr)
Sichere ProgrammierungClaude Opus 5.5 is now available in GitHub Copilot(22.09.2026 um 19:10 Uhr)
Sichere ProgrammierungColab is now part of your Google AI plan(22.09.2026 um 20:51 Uhr)
Sichere ProgrammierungThe Hidden Production Risks of Third-Party SDKs(22.09.2026 um 20:00 Uhr)
YouTube Security VideosWelcome to GitHub Copilot Day: the future of agentic engineering(22.09.2026 um 20:00 Uhr)
YouTube Security VideosMicrosoft Mechanics: What Can a Copilot Agent Actually Read?(22.09.2026 um 20:27 Uhr)
Unix & Linux ServerPeppermintOS Is Moving From Xorg to XLibre to Avoid Wayland(22.09.2026 um 19:58 Uhr)
Sicherheitslücken (CVE)USN-8803-1: Sudo vulnerability(22.09.2026 um 16:15 Uhr)
Sichere ProgrammierungClaude Opus 5.5 is now available in GitHub Copilot(22.09.2026 um 19:10 Uhr)
Sichere ProgrammierungColab is now part of your Google AI plan(22.09.2026 um 20:51 Uhr)
Sichere ProgrammierungThe Hidden Production Risks of Third-Party SDKs(22.09.2026 um 20:00 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Write your domain once in C#, ship idiomatic TypeScript with Metano

If you build a full-stack product with a .NET backend and a TypeScript frontend, you have almost certainly described the same domain twice. The User entity, the Order status enum, the small validation rule, the JSON contract: written once…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

If you build a full-stack product with a .NET backend and a TypeScript frontend, you have almost certainly described the same domain twice. The User entity, the Order status enum, the small validation rule, the JSON contract: written once in C#, then mirrored by hand in TypeScript. The mirror drifts. Someone adds a field on one side and forgets the other. A bug ships.



I got tired of maintaining that second copy, so I built Metano.



Metano is a Roslyn-powered transpiler. You keep your domain in C#, as the single source of truth, and Metano generates real TypeScript from it. Not declaration stubs, not just type shapes: actual behavior. Records, methods, operators, guards, LINQ, async, exceptions, and JSON serializer contracts come across as idiomatic TypeScript that fits the tooling you already use.






Why not just use what already exists



A few approaches get close, and each one stops short of what I wanted:





  • Hand-written type mirrors. The honest baseline, and the one that drifts. Every change is two changes, and the compiler on neither side knows about the other.


  • OpenAPI / NSwag codegen. Great for client SDKs and DTO shapes, but it generates data shapes, not behavior. Your ToggleCompleted() method does not come along.


  • Blazor WebAssembly. This ships the .NET runtime into the browser. It is .NET running on the client, not idiomatic TypeScript your frontend team reads and owns, and the runtime weight is real.


  • Fable. Excellent project, but it is built around F#. If your backend and your team live in C#, that is a language switch, not a code-sharing strategy.



Metano sits in the gap: C# in, idiomatic TypeScript out, with no .NET runtime in the browser and only small helper imports when the emitted code actually needs them.






Show, do not tell



Here is a record written in C#:




using Metano.Annotations;

[assembly: TranspileAssembly]
[assembly: EmitPackage("sample-todo")]

namespace SampleTodo;

[StringEnum]
public enum Priority { Low, Medium, High }

public record TodoItem(string Title, bool Completed = false, Priority Priority = Priority.Medium)
{
public TodoItem ToggleCompleted() => this with { Completed = !Completed };

public TodoItem SetPriority(Priority priority) => this with { Priority = priority };

public override string ToString() => $"[{(Completed ? "x" : " ")}] {Title} ({Priority})";
}






And here is what Metano generates:




export const Priority = {
Low: "low",
Medium: "medium",
High: "high",
} as const;

export type Priority = (typeof Priority)[keyof typeof Priority];

export class TodoItem {
constructor(
readonly title: string,
readonly completed: boolean = false,
readonly priority: Priority = "medium",
) {}

toggleCompleted(): TodoItem {
return this.with({ completed: !this.completed });
}

setPriority(priority: Priority): TodoItem {
return this.with({ priority: priority });
}

toString(): string {
return `[${this.completed ? "x" : " "}] ${this.title} (${this.priority})`;
}

equals(other: any): boolean {
return (
other instanceof TodoItem &&
this.title === other.title &&
this.completed === other.completed &&
this.priority === other.priority
);
}

with(overrides?: Partial<TodoItem>): TodoItem {
return new TodoItem(
overrides?.title ?? this.title,
overrides?.completed ?? this.completed,
overrides?.priority ?? this.priority,
);
}
}






The C# record keeps its value semantics on the TypeScript side. You get structural equals, a non-destructive with, and the string enum rendered as a const object plus a union type, which is the idiom most TS codebases already reach for. No decorators to wire up, no runtime to load, just code your bundler treats like any other module.






How it works



Metano is built on Roslyn, so it understands your C# semantically rather than scraping syntax. The pipeline parses your project, lowers it into a shared intermediate representation, and then emits target code from that IR.



TypeScript is the production target today. There is also an experimental Dart/Flutter backend riding the same IR, which exists mostly to validate that the architecture is genuinely multi-target rather than a TypeScript-shaped special case. Keeping the IR honest is what makes new backends tractable later.






What it handles today



More than I expected to reach when I started:




  • C# records, classes, structs, interfaces, delegates, inheritance, generics, overloads, extension methods, nullable types, async, exceptions, pattern matching, and nested types.

  • BCL mappings for collections, LINQ, decimal, Guid, temporal types, BigInteger, tasks, strings, and math.


  • System.Text.Json source-generation metadata is emitted as a TypeScript SerializerContext, so your serialization contracts stay in sync too.

  • Output controls via attributes when you want to shape the emitted code: [StringEnum], [PlainObject], [Branded], [GenerateGuard], [ObjectArgs], [Optional], [Import], and more.

  • Cross-project package generation with [EmitPackage], generated barrels, and package-aware imports.



The generated TypeScript works with Bun, Vite, Vitest, Biome, ESLint, bundlers, and source maps. It behaves like code a person wrote.






Honest scope



Metano is young and moving quickly. TypeScript is the mature, production path; the Dart backend is intentionally documented as experimental while its coverage grows. It is built for sharing domain code and logic, not for porting an entire app or replacing your UI framework, although the repo does include a set of counter samples that explore component and MVU-style patterns, including SolidJS interop, if you want to see how far the idea stretches.



If you are looking for "write C# and never touch the frontend again," that is not what this is. If you are looking for "stop maintaining a second copy of my domain," that is exactly this.






Try it






dotnet add package Metano
dotnet add package Metano.Build






Point your C# project at a generated TypeScript package:




<PropertyGroup>
<MetanoOutputDir>../my-domain-ts/src</MetanoOutputDir>
<MetanoClean>true</MetanoClean>
</PropertyGroup>






Then dotnet build. There is also a global tool if you prefer manual runs:




dotnet tool install --global Metano.Compiler.TypeScript
dotnet metano-typescript -p path/to/YourProject.csproj -o path/to/output/src --clean











What is next



I will continue to evolve Metano by exploring more use cases and making it more complete, and along the way, I'm evaluating other approaches like JSX generation.



The roadmap I am most curious about is a WebAssembly backend on the same IR, using the modern WasmGC proposal so the output stays lean instead of shipping a runtime. That raises a genuinely interesting compiler problem: how to lower C# value types onto WasmGC's reference-typed structs while preserving copy semantics. I will write that one up separately. Also, evaluate whether using WasmGC will allow me to transfer data between Wasm and JS with minimal friction, which opens up space for more interesting prototypes.



If Metano is useful to you, or if it breaks in an interesting way, I would love your feedback. Issues and stars both help me prioritize.

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Write your domain once in C#, ship idiomatic TypeScript with Metano

Thematisch verwandte Begriffe: Write, your, domain, once · 6 Treffer

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-75517 | Novu provides an API for sending notifications through multiple channels…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick