Skip to content

ts-types Better Support for Types useful for Functions#1

Open
logankaser wants to merge 3 commits intoryangoree:mainfrom
logankaser:main
Open

ts-types Better Support for Types useful for Functions#1
logankaser wants to merge 3 commits intoryangoree:mainfrom
logankaser:main

Conversation

@logankaser
Copy link
Copy Markdown

@logankaser logankaser commented Mar 28, 2026

Background

It all started when I decided a good DX for my embedding my Rust app inside an existing React app, was to follow common
JS patterns, and have my Rust app take an object of callback functions at startup. They led me down quite the rabbit hole.

Upon discovering that tsify despite the excellent name, is sadly Serde-based and therefore uses JSON for FFI (gross)
and does not support Function as a result, I was sad.

Then, I discovered your library ts_macro which does support Function. Reading your code, I noticed that for unhandled types, it just used the name of the type in TypeScript.
Presumably so that if someone uses typescript_custom_section, it will do the right thing.

This meant if I could make a thing that turned function types in Rust into TypeScript types, I would be able to use ts-macro to allow my module to take a struct of typed callbacks at startup. Which is a good pattern for Rust >JS communication, especially for my application, which runs / loops in requestAnimationFrame, so just return values from functions are not really enough.

While adapting ts-types to the Function types use case, I had to make a few changes to better support function types, and also for performance reasons.

Here's what I did:

  • Upgrade to Syn 2.0
  • Migrated from regex-based parsing to direct AST traversal for Option, Vec, and other containers. This allows for reliable mapping of deeply nested types (e.g., Option<Vec<String>>).
    This allowed me to drop the deps on regex and lazy_static entirely.
  • Added support for mapping generic type parameters recursively, enabling types like Result<String, i32> to correctly output Result<string, number>. This is a lot more important for functions than it is for structs, as you might imagine, as result types are pretty important there.
  • Updated the mapping logic to treat Arc<T>, Rc<T>, and Box<T> as transparent wrappers, ensuring the TypeScript definitions focus on the underlying data. This is really only useful for when you're wrapping a Rust struct that might not have been made for the ts macro and also makes that macro and my function macro a little more flexible.
  • TypedArray Mapping: Collection types for primitives (like u8 or f64) now automatically map to their high-performance JavaScript equivalents, such as Uint8Array or Float64Array. This avoids expensive element-by-element copying of number[]. Probably more significant for functions than for structs most of the time. This also matches the behavior of wasm-bindgen itself for functions, which I think is more intuitive.
  • Fixed a bug where slices were being treated as single-element TypeScript tuples:
    strip_type helper was stringifying the Rust slice type &[u8] as the string "[u8]". Because that string uses square brackets, the TypeScript parser (correctly) identified it as a TypeScript tuple of length 1, rather than a TypeScript array.
    The helper now produces "u8[]" instead of "[u8]", so it correctly parses as an array.
    Also, I updated TsType::try_from to handle Type::Slice and Vec<T> directly at the AST level. It now explicitly constructs a TsType::Array (which correctly renders as T[]), bypassing the string parser entirely for these common types.
    As a side effect, Vec<Vec<f64>> now correctly maps to Float64Array[] (an array of Float64Array)

@logankaser logankaser changed the title Backport ts-types changes for my function types macro ts-types Better Support for Types useful for Functions Apr 2, 2026
@logankaser
Copy link
Copy Markdown
Author

logankaser commented Apr 3, 2026

I ended up including the updated version of ts-types in https://crates.io/crates/ts-function, but it would be great to switch back to the official version in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant