diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb011913..1bc7f5ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,10 @@
- `#[serde(with = "...")]` requires the use of `#[ts(as = "...")]` or `#[ts(type = "...")]` ([#280](https://github.com/Aleph-Alpha/ts-rs/pull/280))
- Fix incompatibility with serde for `snake_case`, `kebab-case` and `SCREAMING_SNAKE_CASE` ([#298](https://github.com/Aleph-Alpha/ts-rs/pull/298))
- `#[ts(rename_all = "...")]` no longer accepts variations in the string's casing, dashes and underscores to make behavior consistent with serde ([#298](https://github.com/Aleph-Alpha/ts-rs/pull/298))
+- Remove `TypeList`, and replace `TS::dependency_types`/`TS::generics` with `TS::visit_dependencies`/`TS::visit_generics`.
+ This finally resolves "overflow evaluating the requirement", "reached the recursion limit" errors.
+ Also, compile times should benefit. This is a technically breaking change for those interacting with the `TS` trait
+ directly. For those just using `#[derive(TS)]` and `#[ts(...)]`, nothing changes!
### Features
diff --git a/README.md b/README.md
index 623ca0b2..6d019aee 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,6 @@ 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.75.0
+The Minimum Supported Rust Version for this crate is 1.63.0
License: MIT
diff --git a/macros/src/deps.rs b/macros/src/deps.rs
index e38c96c5..ef61084a 100644
--- a/macros/src/deps.rs
+++ b/macros/src/deps.rs
@@ -79,13 +79,11 @@ impl Dependencies {
impl ToTokens for Dependencies {
fn to_tokens(&self, tokens: &mut TokenStream) {
- let crate_rename = &self.crate_rename;
let lines = self.dependencies.iter();
- tokens.extend(quote![{
- use #crate_rename::typelist::TypeList;
- ()#(#lines)*
- }]);
+ tokens.extend(quote![
+ #(#lines;)*
+ ]);
}
}
@@ -93,12 +91,12 @@ impl ToTokens for Dependency {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(match self {
Dependency::Transitive { crate_rename, ty } => {
- quote![.extend(<#ty as #crate_rename::TS>::dependency_types())]
+ quote![<#ty as #crate_rename::TS>::visit_dependencies(v)]
}
Dependency::Generics { crate_rename, ty } => {
- quote![.extend(<#ty as #crate_rename::TS>::generics())]
+ quote![<#ty as #crate_rename::TS>::visit_generics(v)]
}
- Dependency::Type(ty) => quote![.push::<#ty>()],
+ Dependency::Type(ty) => quote![v.visit::<#ty>()],
});
}
}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index 9e1f40aa..845d2af3 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -92,8 +92,7 @@ impl DerivedTS {
#generics_fn
#output_path_fn
- #[allow(clippy::unused_unit)]
- fn dependency_types() -> impl #crate_rename::typelist::TypeList
+ fn visit_dependencies(v: &mut impl #crate_rename::TypeVisitor)
where
Self: 'static,
{
@@ -195,15 +194,18 @@ impl DerivedTS {
let generics = generics
.type_params()
.filter(|ty| !self.concrete.contains_key(&ty.ident))
- .map(|TypeParam { ident, .. }| quote![.push::<#ident>().extend(<#ident as #crate_rename::TS>::generics())]);
+ .map(|TypeParam { ident, .. }| {
+ quote![
+ v.visit::<#ident>();
+ <#ident as #crate_rename::TS>::visit_generics(v);
+ ]
+ });
quote! {
- #[allow(clippy::unused_unit)]
- fn generics() -> impl #crate_rename::typelist::TypeList
+ fn visit_generics(v: &mut impl #crate_rename::TypeVisitor)
where
Self: 'static,
{
- use #crate_rename::typelist::TypeList;
- ()#(#generics)*
+ #(#generics)*
}
}
}
diff --git a/macros/src/utils.rs b/macros/src/utils.rs
index 93dfbd58..07ce47a2 100644
--- a/macros/src/utils.rs
+++ b/macros/src/utils.rs
@@ -97,7 +97,7 @@ pub fn raw_name_to_ts_field(value: String) -> String {
}
/// Parse all `#[ts(..)]` attributes from the given slice.
-pub fn parse_attrs<'a, A>(attrs: &'a [Attribute]) -> Result
+pub(crate) fn parse_attrs<'a, A>(attrs: &'a [Attribute]) -> Result
where
A: TryFrom<&'a Attribute, Error = Error> + Attr,
{
diff --git a/ts-rs/Cargo.toml b/ts-rs/Cargo.toml
index 27a66611..ae3eba83 100644
--- a/ts-rs/Cargo.toml
+++ b/ts-rs/Cargo.toml
@@ -15,7 +15,7 @@ categories = [
"web-programming",
]
readme = "../README.md"
-rust-version = "1.75.0"
+rust-version = "1.63.0"
[features]
chrono-impl = ["chrono"]
diff --git a/ts-rs/src/export.rs b/ts-rs/src/export.rs
index 07d35dfc..50434187 100644
--- a/ts-rs/src/export.rs
+++ b/ts-rs/src/export.rs
@@ -35,10 +35,7 @@ mod recursive_export {
use std::{any::TypeId, collections::HashSet, path::Path};
use super::export_into;
- use crate::{
- typelist::{TypeList, TypeVisitor},
- ExportError, TS,
- };
+ use crate::{ExportError, TypeVisitor, TS};
/// Exports `T` to the file specified by the `#[ts(export_to = ..)]` attribute within the given
/// base directory.
@@ -85,7 +82,7 @@ mod recursive_export {
out_dir,
error: None,
};
- T::dependency_types().for_each(&mut visitor);
+ T::visit_dependencies(&mut visitor);
if let Some(e) = visitor.error {
Err(e)
diff --git a/ts-rs/src/lib.rs b/ts-rs/src/lib.rs
index 5eb7d0e3..a422c594 100644
--- a/ts-rs/src/lib.rs
+++ b/ts-rs/src/lib.rs
@@ -114,7 +114,7 @@
//! [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.75.0
+//! The Minimum Supported Rust Version for this crate is 1.63.0
use std::{
any::TypeId,
@@ -131,14 +131,12 @@ use std::{
pub use ts_rs_macros::TS;
pub use crate::export::ExportError;
-use crate::typelist::TypeList;
#[cfg(feature = "chrono-impl")]
mod chrono;
mod export;
#[cfg(feature = "serde-json-impl")]
mod serde_json;
-pub mod typelist;
/// A type which can be represented in TypeScript.
/// Most of the time, you'd want to derive this trait instead of implementing it manually.
@@ -418,20 +416,19 @@ pub trait TS {
/// This function will panic if the type cannot be inlined.
fn inline() -> String;
- /// Flatten an type declaration.
+ /// Flatten a type declaration.
/// This function will panic if the type cannot be flattened.
fn inline_flattened() -> String;
- /// Returns a [`TypeList`] of all types on which this type depends.
- fn dependency_types() -> impl TypeList
+ /// Iterates over all dependency of this type.
+ fn visit_dependencies(_: &mut impl TypeVisitor)
where
Self: 'static,
{
}
- /// Returns a [`TypeList`] containing all generic parameters of this type.
- /// If this type is not generic, this will return an empty [`TypeList`].
- fn generics() -> impl TypeList
+ /// Iterates over all type parameters of this type.
+ fn visit_generics(_: &mut impl TypeVisitor)
where
Self: 'static,
{
@@ -442,8 +439,6 @@ pub trait TS {
where
Self: 'static,
{
- use crate::typelist::TypeVisitor;
-
let mut deps: Vec = vec![];
struct Visit<'a>(&'a mut Vec);
impl<'a> TypeVisitor for Visit<'a> {
@@ -453,7 +448,7 @@ pub trait TS {
}
}
}
- Self::dependency_types().for_each(&mut Visit(&mut deps));
+ Self::visit_dependencies(&mut Visit(&mut deps));
deps
}
@@ -530,7 +525,7 @@ pub trait TS {
}
/// Manually generate bindings for this type, returning a [`String`].
- /// This function does not format the output, even if the `format` feature is enabled. TODO
+ /// This function does not format the output, even if the `format` feature is enabled.
///
/// # Automatic Exporting
/// Types annotated with `#[ts(export)]`, together with all of their dependencies, will be
@@ -578,6 +573,14 @@ pub trait TS {
}
}
+/// A visitor used to iterate over all dependencies or generics of a type.
+/// When an instance of [`TypeVisitor`] is passed to [`TS::visit_dependencies`] or
+/// [`TS::visit_generics`], the [`TypeVisitor::visit`] method will be invoked for every dependency
+/// or generic parameter respectively.
+pub trait TypeVisitor: Sized {
+ fn visit(&mut self);
+}
+
/// A typescript type which is depended upon by other types.
/// This information is required for generating the correct import statements.
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
@@ -625,16 +628,19 @@ macro_rules! impl_tuples {
impl<$($i: TS),*> TS for ($($i,)*) {
type WithoutGenerics = (Dummy, );
fn name() -> String {
- format!("[{}]", [$($i::name()),*].join(", "))
+ format!("[{}]", [$(<$i as $crate::TS>::name()),*].join(", "))
}
fn inline() -> String {
panic!("tuple cannot be inlined!");
}
- fn dependency_types() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static
{
- ()$(.push::<$i>())*
+ $(
+ v.visit::<$i>();
+ <$i>::visit_generics(v);
+ )*
}
fn inline_flattened() -> String { panic!("tuple cannot be flattened") }
fn decl() -> String { panic!("tuple cannot be declared") }
@@ -656,17 +662,19 @@ macro_rules! impl_wrapper {
fn name() -> String { T::name() }
fn inline() -> String { T::inline() }
fn inline_flattened() -> String { T::inline_flattened() }
- fn dependency_types() -> impl $crate::typelist::TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
- Self: 'static
+ Self: 'static,
{
- T::dependency_types()
+ T::visit_dependencies(v);
}
- fn generics() -> impl $crate::typelist::TypeList
+
+ fn visit_generics(v: &mut impl TypeVisitor)
where
- Self: 'static
+ Self: 'static,
{
- ((std::marker::PhantomData::,), T::generics())
+ T::visit_generics(v);
+ v.visit::();
}
fn decl() -> String { panic!("wrapper type cannot be declared") }
fn decl_concrete() -> String { panic!("wrapper type cannot be declared") }
@@ -678,26 +686,26 @@ macro_rules! impl_wrapper {
macro_rules! impl_shadow {
(as $s:ty: $($impl:tt)*) => {
$($impl)* {
- type WithoutGenerics = <$s as TS>::WithoutGenerics;
- fn ident() -> String { <$s>::ident() }
- fn name() -> String { <$s>::name() }
- fn inline() -> String { <$s>::inline() }
- fn inline_flattened() -> String { <$s>::inline_flattened() }
- fn dependency_types() -> impl $crate::typelist::TypeList
+ type WithoutGenerics = <$s as $crate::TS>::WithoutGenerics;
+ fn ident() -> String { <$s as $crate::TS>::ident() }
+ fn name() -> String { <$s as $crate::TS>::name() }
+ fn inline() -> String { <$s as $crate::TS>::inline() }
+ fn inline_flattened() -> String { <$s as $crate::TS>::inline_flattened() }
+ fn visit_dependencies(v: &mut impl $crate::TypeVisitor)
where
- Self: 'static
+ Self: 'static,
{
- <$s>::dependency_types()
+ <$s as $crate::TS>::visit_dependencies(v);
}
- fn generics() -> impl $crate::typelist::TypeList
+ fn visit_generics(v: &mut impl $crate::TypeVisitor)
where
- Self: 'static
+ Self: 'static,
{
- <$s>::generics()
+ <$s as $crate::TS>::visit_generics(v);
}
- fn decl() -> String { <$s>::decl() }
- fn decl_concrete() -> String { <$s>::decl_concrete() }
- fn output_path() -> Option<&'static std::path::Path> { <$s>::output_path() }
+ fn decl() -> String { <$s as $crate::TS>::decl() }
+ fn decl_concrete() -> String { <$s as $crate::TS>::decl_concrete() }
+ fn output_path() -> Option<&'static std::path::Path> { <$s as $crate::TS>::output_path() }
}
};
}
@@ -713,18 +721,19 @@ impl TS for Option {
format!("{} | null", T::inline())
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::dependency_types()
+ T::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::generics().push::()
+ T::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
@@ -751,18 +760,22 @@ impl TS for Result {
format!("{{ Ok : {} }} | {{ Err : {} }}", T::inline(), E::inline())
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::dependency_types().extend(E::dependency_types())
+ T::visit_dependencies(v);
+ E::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::generics().push::().extend(E::generics()).push::()
+ T::visit_generics(v);
+ v.visit::();
+ E::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
@@ -793,18 +806,19 @@ impl TS for Vec {
format!("Array<{}>", T::inline())
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::dependency_types()
+ T::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::generics().push::()
+ T::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
@@ -846,18 +860,19 @@ impl TS for [T; N] {
)
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::dependency_types()
+ T::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- T::generics().push::()
+ T::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
@@ -888,18 +903,22 @@ impl TS for HashMap {
format!("{{ [key: {}]: {} }}", K::inline(), V::inline())
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- K::dependency_types().extend(V::dependency_types())
+ K::visit_dependencies(v);
+ V::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- K::generics().push::().extend(V::generics()).push::()
+ K::visit_generics(v);
+ v.visit::();
+ V::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
@@ -921,18 +940,19 @@ impl TS for Range {
format!("{{ start: {}, end: {}, }}", I::name(), I::name())
}
- fn dependency_types() -> impl TypeList
+ fn visit_dependencies(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- I::dependency_types()
+ I::visit_dependencies(v);
}
- fn generics() -> impl TypeList
+ fn visit_generics(v: &mut impl TypeVisitor)
where
Self: 'static,
{
- I::generics().push::()
+ I::visit_generics(v);
+ v.visit::();
}
fn decl() -> String {
diff --git a/ts-rs/src/typelist.rs b/ts-rs/src/typelist.rs
deleted file mode 100644
index 123bf521..00000000
--- a/ts-rs/src/typelist.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-//! A simple zero-sized collection of types.
-
-use std::{any::TypeId, marker::PhantomData};
-
-use crate::TS;
-
-/// A visitor used to iterate over a [`TypeList`].
-///
-/// Example:
-/// ```
-/// # use ts_rs::TS;
-/// # use ts_rs::typelist::{TypeList, TypeVisitor};
-/// struct Visit;
-/// impl TypeVisitor for Visit {
-/// fn visit(&mut self) {
-/// println!("{}", T::name());
-/// }
-/// }
-///
-/// # fn primitives() -> impl TypeList {
-/// # let signed = ().push::().push::().push::().push::();
-/// # let unsigned = ().push::().push::().push::().push::();
-/// # ().push::()
-/// # .push::()
-/// # .extend(signed)
-/// # .extend(unsigned)
-/// # }
-/// // fn primitives() -> impl TypeList { ... }
-/// primitives().for_each(&mut Visit);
-/// ```
-pub trait TypeVisitor: Sized {
- fn visit(&mut self);
-}
-
-/// A list containing types implementing `TS + 'static + ?Sized`.
-///
-/// To construct a [`TypeList`], start with the empty list, which is the unit type `()`, and
-/// repeatedly call [`TypeList::push`] or [`TypeList::extend`] on it.
-///
-/// Example:
-/// ```
-/// # use ts_rs::typelist::TypeList;
-/// fn primitives() -> impl TypeList {
-/// let signed = ().push::().push::().push::().push::();
-/// let unsigned = ().push::().push::().push::().push::();
-/// ().push::()
-/// .push::()
-/// .extend(signed)
-/// .extend(unsigned)
-/// }
-/// ```
-///
-/// The only way to get access to the types contained in a [`TypeList`] is to iterate over it by
-/// creating a visitor implementing [`TypeVisitor`] and calling [`TypeList::for_each`].
-///
-/// Under the hood, [`TypeList`] is recursively defined as follows:
-/// - The unit type `()` is the empty [`TypeList`]
-/// - For every `T: TS`, `(PhantomData,)` is a [`TypeList`]
-/// - For every two [`TypeList`]s `A` and `B`, `(A, B)` is a [`TypeList`]
-pub trait TypeList: Copy + Clone {
- fn push(self) -> impl TypeList {
- (self, (PhantomData::,))
- }
- fn extend(self, l: impl TypeList) -> impl TypeList {
- (self, l)
- }
-
- fn contains(self) -> bool;
- fn for_each(self, v: &mut impl TypeVisitor);
-}
-
-impl TypeList for () {
- fn contains(self) -> bool {
- false
- }
- fn for_each(self, _: &mut impl TypeVisitor) {}
-}
-
-impl TypeList for (PhantomData,)
-where
- T: TS + 'static + ?Sized,
-{
- fn contains(self) -> bool {
- TypeId::of::() == TypeId::of::()
- }
-
- fn for_each(self, v: &mut impl TypeVisitor) {
- v.visit::();
- }
-}
-
-impl TypeList for (A, B)
-where
- A: TypeList,
- B: TypeList,
-{
- fn contains(self) -> bool {
- self.0.contains::() || self.1.contains::()
- }
-
- fn for_each(self, v: &mut impl TypeVisitor) {
- self.0.for_each(v);
- self.1.for_each(v);
- }
-}
diff --git a/ts-rs/tests/integration/issue_308.rs b/ts-rs/tests/integration/issue_308.rs
index 6e2faf5b..41fc5e79 100644
--- a/ts-rs/tests/integration/issue_308.rs
+++ b/ts-rs/tests/integration/issue_308.rs
@@ -1,6 +1,6 @@
use std::path::{Path, PathBuf};
-use ts_rs::{typelist::TypeList, Dependency, ExportError, TS};
+use ts_rs::{Dependency, ExportError, TypeVisitor, TS};
#[rustfmt::skip]
trait Malicious {
@@ -13,9 +13,9 @@ trait Malicious {
fn name() -> String { unimplemented!() }
fn inline() -> String { unimplemented!() }
fn inline_flattened() -> String { unimplemented!() }
- fn dependency_types() -> impl TypeList {}
- fn generics() -> impl TypeList {}
fn dependencies() -> Vec { unimplemented!() }
+ fn visit_dependencies(_: &mut impl TypeVisitor) { unimplemented!() }
+ fn visit_generics(_: &mut impl TypeVisitor) { unimplemented!() }
fn export() -> Result<(), ExportError> { unimplemented!() }
fn export_all() -> Result<(), ExportError> { unimplemented!() }
fn export_all_to(out_dir: impl AsRef) -> Result<(), ExportError> { unimplemented!() }
diff --git a/ts-rs/tests/integration/issue_317.rs b/ts-rs/tests/integration/issue_317.rs
new file mode 100644
index 00000000..bc286baa
--- /dev/null
+++ b/ts-rs/tests/integration/issue_317.rs
@@ -0,0 +1,18 @@
+use ts_rs::TS;
+
+#[derive(TS)]
+#[ts(export_to = "issue_317/")]
+struct VariantId(u32);
+
+#[derive(TS)]
+#[ts(export_to = "issue_317/")]
+struct VariantOverview {
+ id: u32,
+ name: String
+}
+
+#[derive(TS)]
+#[ts(export, export_to = "issue_317/")]
+struct Container {
+ variants: Vec<(VariantId, VariantOverview)>,
+}
diff --git a/ts-rs/tests/integration/main.rs b/ts-rs/tests/integration/main.rs
index 62bbeab0..6eeef9f8 100644
--- a/ts-rs/tests/integration/main.rs
+++ b/ts-rs/tests/integration/main.rs
@@ -59,3 +59,4 @@ mod union_with_data;
mod union_with_internal_tag;
mod unit;
mod r#unsized;
+mod issue_317;
diff --git a/ts-rs/tests/integration/recursion_limit.rs b/ts-rs/tests/integration/recursion_limit.rs
index 5406120c..16e1a2d2 100644
--- a/ts-rs/tests/integration/recursion_limit.rs
+++ b/ts-rs/tests/integration/recursion_limit.rs
@@ -1,9 +1,6 @@
use std::any::TypeId;
-use ts_rs::{
- typelist::{TypeList, TypeVisitor},
- TS,
-};
+use ts_rs::{TypeVisitor, TS};
#[rustfmt::skip]
#[allow(clippy::all)]
@@ -77,7 +74,36 @@ fn very_big_enum() {
}
let mut visitor = Visitor(false);
- VeryBigEnum::dependency_types().for_each(&mut visitor);
+ VeryBigEnum::visit_dependencies(&mut visitor);
assert!(visitor.0, "there must be at least one dependency");
}
+
+macro_rules! generate_types {
+ ($a:ident, $b:ident $($t:tt)*) => {
+ #[derive(TS)]
+ #[ts(export, export_to = "very_big_types/")]
+ struct $a($b);
+ generate_types!($b $($t)*);
+ };
+ ($a:ident) => {
+ #[derive(TS)]
+ #[ts(export, export_to = "very_big_types/")]
+ struct $a;
+ }
+}
+
+// This generates
+// `#[derive(TS)] struct T000(T001)`
+// `#[derive(TS)] struct T001(T002)`
+// ...
+// `#[derive(TS)] struct T082(T083)`
+// `#[derive(TS)] struct T083;`
+generate_types!(
+ T000, T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015,
+ T016, T017, T018, T019, T020, T021, T022, T023, T024, T025, T026, T027, T028, T029, T030, T031,
+ T032, T033, T034, T035, T036, T037, T038, T039, T040, T041, T042, T043, T044, T045, T046, T047,
+ T048, T049, T050, T051, T052, T053, T054, T055, T056, T057, T058, T059, T060, T061, T062, T063,
+ T064, T065, T066, T067, T068, T069, T070, T071, T072, T073, T074, T075, T076, T077, T078, T079,
+ T080, T081, T082, T083
+);
diff --git a/ts-rs/tests/integration/tuple.rs b/ts-rs/tests/integration/tuple.rs
index 88ecef61..9d85c919 100644
--- a/ts-rs/tests/integration/tuple.rs
+++ b/ts-rs/tests/integration/tuple.rs
@@ -23,12 +23,65 @@ fn test_newtype() {
assert_eq!("type NewType = string;", NewType::decl());
}
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct TupleNewType(String, i32, (i32, i32));
+
#[test]
fn test_tuple_newtype() {
- #[derive(TS)]
- struct TupleNewType(String, i32, (i32, i32));
assert_eq!(
"type TupleNewType = [string, number, [number, number]];",
TupleNewType::decl()
)
}
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct Dep1;
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct Dep2;
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct Dep3;
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct Dep4 {
+ a: (T, T),
+ b: (T, T),
+}
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct TupleWithDependencies(Dep1, Dep2, Dep4);
+
+#[test]
+fn tuple_with_dependencies() {
+ assert_eq!(
+ "type TupleWithDependencies = [Dep1, Dep2, Dep4];",
+ TupleWithDependencies::decl()
+ );
+}
+
+#[derive(TS)]
+#[ts(export, export_to = "tuple/")]
+struct StructWithTuples {
+ a: (Dep1, Dep1),
+ b: (Dep2, Dep2),
+ c: (Dep4, Dep4),
+}
+
+#[test]
+fn struct_with_tuples() {
+ assert_eq!(
+ "type StructWithTuples = { \
+ a: [Dep1, Dep1], \
+ b: [Dep2, Dep2], \
+ c: [Dep4, Dep4], \
+ };",
+ StructWithTuples::decl()
+ );
+}