-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
#[ts(concrete)]
: Allow generic parameter to be "disabled"
#264
Conversation
How exactly should
|
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
#[ts(discrete)]
: Allow generic parameter to be "disabled"#[ts(concrete)]
: Allow generic parameter to be "disabled"
This comment was marked as outdated.
This comment was marked as outdated.
😆 A typo, was studying maths before, I think that's where that came from ^^
Correct, sorry about that. I think the 2nd snippet wouldn't even compile as-is. Fixed!
I think allowing that is intended, see #261 for @WilsonGramer's usecase.
Good question! So this prototype here kind of works, but I'll have to go back and see why exactly 😆 But in general: We couldn't deal with trait bounds before because we're generating dummy types and plugging them into the generic parameters. If there's a trait bound we don't know about, we can't do that. |
This comment was marked as resolved.
This comment was marked as resolved.
I'm definetely still open to alternative solutions to the "associated types" problem! "There are associated types in the struct" |
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
Was just about to write that I think it just works. We're doing a There are a few interesting edge-cases though, so tests would be great! |
This comment was marked as resolved.
This comment was marked as resolved.
Right! #[derive(TS)]
struct OtherDriver;
impl Driver for OtherDriver {
type Info = Foo;
}
#[derive(TS)]
#[ts(concrete(T = OtherDriver))]
struct OtherStruct<T: Driver> {
u: T::Info,
x: T,
} But: The Maybe we could generate an |
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
Ah, that's very annoying! fn get_info_name<T: Driver>() -> String {
<T::Info as TS>::name()
} Seems like a tough problem. If you'd like, i'd be happy to take a look if you push it to a new branch. Getting the feeling that it might be difficult without doing too much special-casing though. |
Agreed. What could make this even more complicated is the fact that we'd have to handle both struct MyStruct<T: Driver> and struct MyStruct<T> where T: Driver |
It might even be impossible - what if there are two trait bounds? struct MyStruct<D: Driver + Context> {
info: D::Info,
ctx: D::Ctx,
} ( Then, we'd have to figure out where the associated type came from to use that syntax, which we cant. |
There, only the 2nd approach using a helper function seems to work: fn helper<T: Driver + Context>() {
let x = <T::Ctx as TS>::name(); // works
let y = <T::Info as TS>::name(); // works
} |
This comment was marked as resolved.
This comment was marked as resolved.
Is there anything you think still needs to be done here? I'm pretty happy with where this ended up, especially with the new trait bounds 😊 |
There is nothing I can think of, from my side this is ready for merge. @WilsonGramer in its current state does this PR fully resolve your issue?
Me too! And creating that filter function turned out to be a lot of fun :D |
@@ -4,7 +4,7 @@ mod issue_261 { | |||
use ts_rs::TS; | |||
|
|||
trait Driver { | |||
type Info: TS; | |||
type Info; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to show : TS
is no longer needed here
I think it may be a while until he responds, maybe we should merge this and if needed @WilsonGramer can open a new issue. This PR is already getting way too long anyway |
@escritorio-gustavo @NyxCode Sorry for the delay, I will test it now! |
@escritorio-gustavo It looks like this example with nested structs fails to compile: use ts_rs::TS;
trait Driver {
type Info;
}
struct TsDriver;
#[derive(TS)]
struct TsInfo;
impl Driver for TsDriver {
type Info = TsInfo;
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Inner<D: Driver> {
info: D::Info,
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Outer<D: Driver> {
inner: Inner<D>,
}
I think it's adding the bound to |
If I add a use ts_rs::TS;
trait Driver {
type Info: TS;
}
struct TsDriver;
#[derive(TS)]
struct TsInfo;
impl Driver for TsDriver {
type Info = TsInfo;
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Inner<D: Driver> {
info: D::Info,
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Outer<D: Driver> {
inner: Inner<D>,
}
I believe this is the same issue — it thinks |
I am not sure there's anything we can do to automatically fix this, since that would require use ts_rs::TS;
trait Driver {
type Info;
}
#[derive(TS)]
struct TsDriver;
#[derive(TS)]
struct TsInfo;
impl Driver for TsDriver {
type Info = TsInfo;
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Inner<D: Driver> {
info: D::Info,
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Outer<D: Driver>
where
D::Info: TS,
{
inner: Inner<D>,
} You'd need to derive |
Alternatively, this also compiles: use ts_rs::TS;
trait Driver {
type Info: TS;
}
#[derive(TS)]
struct TsDriver;
#[derive(TS)]
struct TsInfo;
impl Driver for TsDriver {
type Info = TsInfo;
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Inner<D: Driver> {
info: D::Info,
}
#[derive(TS)]
#[ts(export, concrete(D = TsDriver))]
struct Outer<D: Driver> {
inner: Inner<D>,
} |
Either way, you need |
@escritorio-gustavo What do you think about adding a #[derive(TS)]
#[ts(export, concrete(D = TsDriver), bound = "")]
struct Outer<D: Driver> {
inner: Inner<D>,
} That way the |
Yeah, I don't think there's a better trait bound we can generate here. |
I've never used it either, I think this should be a brand new issue & PR showing the desired macro expansion, this PR is getting hard to follow |
#[derive(TS)]
#[ts(export, concrete(D = TsDriver), bound = "")]
struct Outer<D: Driver> {
inner: Inner<D>,
} Here, the bound would still need to be My suggestion would be to - unless there's something missing in this PR - merge this first, and tackle a potential The easiest approach there would be to have |
I think opening a new PR for the |
Awesome, thanks! Then we're all set & can merge this? |
This PR aims to allow users to "disable" a generic parameter:
should behave as if the struct was declared without the generic parameter
Y
:Motivation
The main motivation behind this are associated types, which have no equivalent in TypeScript.
Therefore, given a type like this, there's no generic TypeScript type we could generate:
The solution here is to "disable" the generic parameter "Y" by making it "concrete".
TODOs
TS::decl
andTS::decl_concrete
should behavedecl
is clear, anddecl_concrete
still uses the actual type parameters, even if#[ts(concrete)]
is present.TS::generics
though.