Home About Eric Topics SourceGear

2023-05-03 13:00:00

Native AOT libraries with TypeScript

This is part of a series on Native AOT.
Previous -- Top


A few weeks ago I published some samples showing the use of Native AOT libraries from Rust. As I mentioned, the projection of .NET APIs to Rust requires quite a few ergonomic compromises. For example, the following line in C# is a call to the QuestPDF method to set the size of a page:

    page.Size(PageSizes.Letter);

But the Rust projection is messier:

    page.Size_PageSize(&PageSizes::get_Letter()?)?;

Rust also lacks other things that .NET wants, including optional parameters, property getters/setters, and inheritance. Because of all these differences, Rust for general .NET development would typically involve too much pain to be practical.

But the nice thing about Native AOT libraries, is that they can be used with anything that can call C.

Hello TypeScript

TypeScript has method overloads, exceptions, property getters/setters, and inheritance. Hmmm.

For the last few weeks, I've been adding TypeScript as another output language for my binding generator. Things are in a rough state, but the results look positive, so I have published a nuget package and a working port of the QuestPDF sample. That sample is short, but it involves things like generic delegates and extension methods, so I consider it non-trivial.

Interop between any two languages will always involve trouble spots, but TypeScript can look awfully similar to C#. Here's a visual diff from the Quest PDF sample, with TypeScript on the left, and C# on the right:

All of the differences here are because I am projecting nullability more strictly than it is in C#. I currently think this is a feature rather than a bug, but I'm not completely settled on that, and if I stopped doing it this way, these two snippets would actually be identical.

To be fair, let's acknowledge that this is just one sample. TypeScript lacks several things that require extra effort for .NET interop, including:

I mean, if TypeScript were exactly like C#, it would be C#.

Still, I see potential here.

Details

The binding generator itself is contained in a nuget package:

https://www.nuget.org/packages/SourceGear.Bridge.NativeAOT.TypeScript/0.6.0

The QuestPDF sample is in the samples/typescript directory of this repo:

https://github.com/sourcegear/bridge-info

For this prototype, all the FFI-level stuff is setup for Deno (apologies to fans of node).

Related

There's something going on in the following repo:

https://github.com/microsoft/node-api-dotnet

I'm not super-clear on where that project is headed. And there are significant differences relative to what I'm doing, but also some common ground. I think it looks interesting.

Next steps

I'm hoping that I will soon have an AvaloniaUI sample (it's a fair bit more complicated). Down the road a bit, I'd love to get this working with [at least the desktop versions of] MAUI, but I'm not sure yet what will be feasible.

If you have any questions or feedback, please feel free to post in the Discussions or Issues area of the sourcegear/bridge-info repo linked above.