From 0a444d8997f42a78a1c684d451ce0a591137beaf Mon Sep 17 00:00:00 2001 From: Valchap Date: Sat, 6 Sep 2025 21:00:42 +0200 Subject: [PATCH 1/3] Add no-big-int feature --- README.md | 48 +++++++++++++++++++++++++++++------------------- ts-rs/Cargo.toml | 5 ++++- ts-rs/src/lib.rs | 15 +++++++++++++++ 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d9dfe918..a132d61d 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ alt="Download" /> ### Why? + When building a web application in rust, data structures have to be shared between backend and frontend. Using this library, you can easily generate TypeScript bindings to your rust structs & enums so that you can keep your types in one place. @@ -34,12 +35,14 @@ types in one place. ts-rs might also come in handy when working with webassembly. ### How? + ts-rs exposes a single trait, `TS`. Using a derive macro, you can implement this interface for your types. Then, you can use this trait to obtain the TypeScript bindings. We recommend doing this in your tests. [See the example](https://github.com/Aleph-Alpha/ts-rs/blob/main/example/src/lib.rs) and [the docs](https://docs.rs/ts-rs/latest/ts_rs/). ### Get started + ```toml [dependencies] ts-rs = "10.1" @@ -61,10 +64,11 @@ When running `cargo test` or `cargo test export_bindings`, the TypeScript bindin and will contain the following code: ```ts -export type User = { user_id: number, first_name: string, last_name: string, }; +export type User = { user_id: number; first_name: string; last_name: string }; ``` ### Features + - generate type declarations from rust structs - generate union declarations from rust enums - inline types @@ -75,24 +79,26 @@ export type User = { user_id: number, first_name: string, last_name: string, }; - support for ESM imports ### cargo features -| **Feature** | **Description** | -|:-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| serde-compat | **Enabled by default**
See the *"serde compatibility"* section below for more information. | -| format | Enables formatting of the generated TypeScript bindings.
Currently, this unfortunately adds quite a few dependencies. | -| no-serde-warnings | By default, warnings are printed during build if unsupported serde attributes are encountered.
Enabling this feature silences these warnings. | -| serde-json-impl | Implement `TS` for types from *serde_json* | -| chrono-impl | Implement `TS` for types from *chrono* | -| bigdecimal-impl | Implement `TS` for types from *bigdecimal* | -| url-impl | Implement `TS` for types from *url* | -| uuid-impl | Implement `TS` for types from *uuid* | -| bson-uuid-impl | Implement `TS` for *bson::oid::ObjectId* and *bson::uuid* | -| bytes-impl | Implement `TS` for types from *bytes* | -| indexmap-impl | Implement `TS` for types from *indexmap* | -| ordered-float-impl | Implement `TS` for types from *ordered_float* | -| heapless-impl | Implement `TS` for types from *heapless* | -| semver-impl | Implement `TS` for types from *semver* | -| smol_str-impl | Implement `TS` for types from *smol_str* | -| tokio-impl | Implement `TS` for types from *tokio* | + +| **Feature** | **Description** | +| :----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| serde-compat | **Enabled by default**
See the _"serde compatibility"_ section below for more information. | +| format | Enables formatting of the generated TypeScript bindings.
Currently, this unfortunately adds quite a few dependencies. | +| no-serde-warnings | By default, warnings are printed during build if unsupported serde attributes are encountered.
Enabling this feature silences these warnings. | +| serde-json-impl | Implement `TS` for types from _serde_json_ | +| chrono-impl | Implement `TS` for types from _chrono_ | +| bigdecimal-impl | Implement `TS` for types from _bigdecimal_ | +| url-impl | Implement `TS` for types from _url_ | +| uuid-impl | Implement `TS` for types from _uuid_ | +| bson-uuid-impl | Implement `TS` for _bson::oid::ObjectId_ and _bson::uuid_ | +| bytes-impl | Implement `TS` for types from _bytes_ | +| indexmap-impl | Implement `TS` for types from _indexmap_ | +| ordered-float-impl | Implement `TS` for types from _ordered_float_ | +| heapless-impl | Implement `TS` for types from _heapless_ | +| semver-impl | Implement `TS` for types from _semver_ | +| smol_str-impl | Implement `TS` for types from _smol_str_ | +| tokio-impl | Implement `TS` for types from _tokio_ | +| no-big-int | Always bind primitive integers to raw javascript numbers even when this could lead to precision loss |
@@ -100,8 +106,10 @@ If there's a type you're dealing with which doesn't implement `TS`, use either `#[ts(as = "..")]` or `#[ts(type = "..")]`, or open a PR. ### `serde` compatability + With the `serde-compat` feature (enabled by default), serde attributes can be parsed for enums and structs. Supported serde attributes: + - `rename` - `rename-all` - `rename-all-fields` @@ -123,11 +131,13 @@ from the generated type, but cannot use `#[serde(skip)]`, use `#[ts(skip)]` inst When ts-rs encounters an unsupported serde attribute, a warning is emitted, unless the feature `no-serde-warnings` is enabled. ### Contributing + Contributions are always welcome! Feel free to open an issue, discuss using GitHub discussions or open a PR. [See CONTRIBUTING.md](https://github.com/Aleph-Alpha/ts-rs/blob/main/CONTRIBUTING.md) ### MSRV + The Minimum Supported Rust Version for this crate is 1.78.0 License: MIT diff --git a/ts-rs/Cargo.toml b/ts-rs/Cargo.toml index a9d300af..1106d3c6 100644 --- a/ts-rs/Cargo.toml +++ b/ts-rs/Cargo.toml @@ -36,6 +36,7 @@ serde-json-impl = ["serde_json"] no-serde-warnings = ["ts-rs-macros/no-serde-warnings"] import-esm = [] tokio-impl = ["tokio"] +no-big-int = [] [dev-dependencies] serde = { version = "1.0", features = ["derive"] } @@ -50,7 +51,9 @@ thiserror = "2" heapless = { version = ">= 0.7, < 0.9", optional = true } dprint-plugin-typescript = { version = "0.90", optional = true } chrono = { version = "0.4", optional = true } -bigdecimal = { version = ">= 0.0.13, < 0.5", features = ["serde"], optional = true } +bigdecimal = { version = ">= 0.0.13, < 0.5", features = [ + "serde", +], optional = true } uuid = { version = "1", optional = true } bson = { version = "2", optional = true } bytes = { version = "1", optional = true } diff --git a/ts-rs/src/lib.rs b/ts-rs/src/lib.rs index 525f9ca2..9319b74c 100644 --- a/ts-rs/src/lib.rs +++ b/ts-rs/src/lib.rs @@ -1124,6 +1124,7 @@ mod bytes { impl_shadow!(as Vec: impl TS for bytes::BytesMut); } +#[cfg(not(feature = "no-big-int"))] impl_primitives! { u8, i8, NonZeroU8, NonZeroI8, u16, i16, NonZeroU16, NonZeroI16, @@ -1137,6 +1138,20 @@ impl_primitives! { () => "null" } +#[cfg(feature = "no-big-int")] +impl_primitives! { + u8, i8, NonZeroU8, NonZeroI8, + u16, i16, NonZeroU16, NonZeroI16, + u32, i32, NonZeroU32, NonZeroI32, + usize, isize, NonZeroUsize, NonZeroIsize, f32, f64, + u64, i64, NonZeroU64, NonZeroI64, + u128, i128, NonZeroU128, NonZeroI128 => "number", + bool => "boolean", + char, Path, PathBuf, String, str, + Ipv4Addr, Ipv6Addr, IpAddr, SocketAddrV4, SocketAddrV6, SocketAddr => "string", + () => "null" +} + #[rustfmt::skip] pub(crate) use impl_primitives; #[rustfmt::skip] From cf4872e7ea5b80fc6e19a05527f94b1283c1c31b Mon Sep 17 00:00:00 2001 From: Valchap Date: Sat, 6 Sep 2025 21:46:17 +0200 Subject: [PATCH 2/3] Update lib.rs and use it to generate README --- README.md | 12 +----------- ts-rs/src/lib.rs | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index a132d61d..7c45e397 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ alt="Download" /> ### Why? - When building a web application in rust, data structures have to be shared between backend and frontend. Using this library, you can easily generate TypeScript bindings to your rust structs & enums so that you can keep your types in one place. @@ -35,14 +34,12 @@ types in one place. ts-rs might also come in handy when working with webassembly. ### How? - ts-rs exposes a single trait, `TS`. Using a derive macro, you can implement this interface for your types. Then, you can use this trait to obtain the TypeScript bindings. We recommend doing this in your tests. [See the example](https://github.com/Aleph-Alpha/ts-rs/blob/main/example/src/lib.rs) and [the docs](https://docs.rs/ts-rs/latest/ts_rs/). ### Get started - ```toml [dependencies] ts-rs = "10.1" @@ -64,11 +61,10 @@ When running `cargo test` or `cargo test export_bindings`, the TypeScript bindin and will contain the following code: ```ts -export type User = { user_id: number; first_name: string; last_name: string }; +export type User = { user_id: number, first_name: string, last_name: string, }; ``` ### Features - - generate type declarations from rust structs - generate union declarations from rust enums - inline types @@ -78,8 +74,6 @@ export type User = { user_id: number; first_name: string; last_name: string }; - generic types - support for ESM imports -### cargo features - | **Feature** | **Description** | | :----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | serde-compat | **Enabled by default**
See the _"serde compatibility"_ section below for more information. | @@ -106,10 +100,8 @@ If there's a type you're dealing with which doesn't implement `TS`, use either `#[ts(as = "..")]` or `#[ts(type = "..")]`, or open a PR. ### `serde` compatability - With the `serde-compat` feature (enabled by default), serde attributes can be parsed for enums and structs. Supported serde attributes: - - `rename` - `rename-all` - `rename-all-fields` @@ -131,13 +123,11 @@ from the generated type, but cannot use `#[serde(skip)]`, use `#[ts(skip)]` inst When ts-rs encounters an unsupported serde attribute, a warning is emitted, unless the feature `no-serde-warnings` is enabled. ### Contributing - Contributions are always welcome! Feel free to open an issue, discuss using GitHub discussions or open a PR. [See CONTRIBUTING.md](https://github.com/Aleph-Alpha/ts-rs/blob/main/CONTRIBUTING.md) ### MSRV - The Minimum Supported Rust Version for this crate is 1.78.0 License: MIT diff --git a/ts-rs/src/lib.rs b/ts-rs/src/lib.rs index 9319b74c..f21308ee 100644 --- a/ts-rs/src/lib.rs +++ b/ts-rs/src/lib.rs @@ -72,25 +72,25 @@ //! - generic types //! - support for ESM imports //! -//! ## cargo features -//! | **Feature** | **Description** | -//! |:-------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -//! | serde-compat | **Enabled by default**
See the *"serde compatibility"* section below for more information. | -//! | format | Enables formatting of the generated TypeScript bindings.
Currently, this unfortunately adds quite a few dependencies. | -//! | no-serde-warnings | By default, warnings are printed during build if unsupported serde attributes are encountered.
Enabling this feature silences these warnings. | -//! | serde-json-impl | Implement `TS` for types from *serde_json* | -//! | chrono-impl | Implement `TS` for types from *chrono* | -//! | bigdecimal-impl | Implement `TS` for types from *bigdecimal* | -//! | url-impl | Implement `TS` for types from *url* | -//! | uuid-impl | Implement `TS` for types from *uuid* | -//! | bson-uuid-impl | Implement `TS` for *bson::oid::ObjectId* and *bson::uuid* | -//! | bytes-impl | Implement `TS` for types from *bytes* | -//! | indexmap-impl | Implement `TS` for types from *indexmap* | -//! | ordered-float-impl | Implement `TS` for types from *ordered_float* | -//! | heapless-impl | Implement `TS` for types from *heapless* | -//! | semver-impl | Implement `TS` for types from *semver* | -//! | smol_str-impl | Implement `TS` for types from *smol_str* | -//! | tokio-impl | Implement `TS` for types from *tokio* | +//! | **Feature** | **Description** | +//! | :----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +//! | serde-compat | **Enabled by default**
See the _"serde compatibility"_ section below for more information. | +//! | format | Enables formatting of the generated TypeScript bindings.
Currently, this unfortunately adds quite a few dependencies. | +//! | no-serde-warnings | By default, warnings are printed during build if unsupported serde attributes are encountered.
Enabling this feature silences these warnings. | +//! | serde-json-impl | Implement `TS` for types from _serde_json_ | +//! | chrono-impl | Implement `TS` for types from _chrono_ | +//! | bigdecimal-impl | Implement `TS` for types from _bigdecimal_ | +//! | url-impl | Implement `TS` for types from _url_ | +//! | uuid-impl | Implement `TS` for types from _uuid_ | +//! | bson-uuid-impl | Implement `TS` for _bson::oid::ObjectId_ and _bson::uuid_ | +//! | bytes-impl | Implement `TS` for types from _bytes_ | +//! | indexmap-impl | Implement `TS` for types from _indexmap_ | +//! | ordered-float-impl | Implement `TS` for types from _ordered_float_ | +//! | heapless-impl | Implement `TS` for types from _heapless_ | +//! | semver-impl | Implement `TS` for types from _semver_ | +//! | smol_str-impl | Implement `TS` for types from _smol_str_ | +//! | tokio-impl | Implement `TS` for types from _tokio_ | +//! | no-big-int | Always bind primitive integers to raw javascript numbers even when this could lead to precision loss | //! //!
//! From 543fedbc940c06a1e62d86dcf2faccf508434bad Mon Sep 17 00:00:00 2001 From: Valchap Date: Sun, 14 Sep 2025 13:05:36 +0200 Subject: [PATCH 3/3] Fix test cases containing bigint --- .../integration/enum_variant_annotation.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ts-rs/tests/integration/enum_variant_annotation.rs b/ts-rs/tests/integration/enum_variant_annotation.rs index a9107a86..507159a1 100644 --- a/ts-rs/tests/integration/enum_variant_annotation.rs +++ b/ts-rs/tests/integration/enum_variant_annotation.rs @@ -23,6 +23,7 @@ enum A { } #[test] +#[cfg(not(feature = "no-big-int"))] fn test_enum_variant_rename_all() { assert_eq!( A::inline(), @@ -30,6 +31,15 @@ fn test_enum_variant_rename_all() { ); } +#[test] +#[cfg(feature = "no-big-int")] +fn test_enum_variant_rename_all() { + assert_eq!( + A::inline(), + r#"{ "MESSAGE_ONE": { sender_id: string, number_of_snakes: number, } } | { "MESSAGE_TWO": { senderId: string, numberOfCamels: number, } }"#, + ); +} + #[derive(TS)] #[ts(export, export_to = "enum_variant_anotation/")] #[cfg_attr(feature = "serde-compat", derive(Serialize))] @@ -49,6 +59,7 @@ enum B { } #[test] +#[cfg(not(feature = "no-big-int"))] fn test_enum_variant_rename() { assert_eq!( B::inline(), @@ -56,6 +67,15 @@ fn test_enum_variant_rename() { ); } +#[test] +#[cfg(feature = "no-big-int")] +fn test_enum_variant_rename() { + assert_eq!( + B::inline(), + r#"{ "SnakeMessage": { sender_id: string, number_of_snakes: number, } } | { "CamelMessage": { sender_id: string, number_of_camels: number, } }"#, + ); +} + #[derive(TS)] #[ts(export, export_to = "enum_variant_anotation/")] #[cfg_attr(feature = "serde-compat", derive(Serialize))]