-
Notifications
You must be signed in to change notification settings - Fork 509
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
Discussion: Type Aliases should be aliases, not references #429
Comments
This looks like a question for @lukeautry |
In the current framework, yeah, we don't really support type aliases, and the way that we do support them is as a pointer to an interface or a class, so I think your thoughts on this are reasonable. I actually think full support for type aliases makes sense though, i.e. discriminated unions. It's possible that this has been implemented, but to my knowledge it has not. If we have, say:
...the end user is probably thinking about |
Somewhat related: #204. Note that some of the fixed tests refer to new properties on the TestModel and therefore would not be considered a breaking change in any case. |
If you're talking about ValidationErrors, here is what TS does:
type Alias = { num: number }
interface Interface {
num: number;
}
declare function aliased(arg: Alias): Alias;
declare function interfaced(arg: Interface): Interface; |
I think it probably makes sense to align with what TypeScript does, then. |
I almost completely agree with treating aliases as "just symlinks", but there are two reasons why I'd want to keep my aliases in the output: documentation and readability. I like to have aliases like I'm not sure if this is really a "thing" in Swagger/OpenAPI since I don't use it myself (#360 (comment)). For me it would really help with code readability to be able to use the "unexpanded" type aliases in the router output. I'm not saying we should keep things as they are or that we should support every use-case imaginable, we should definitely improve support for type aliases as much as possible. I just wanted to give my two cents on why one would want to keep the original alias names, in the hope that it will be taken into consideration. I don't know the codebase well enough (yet) to know if this would reasonably be possible, but my first instinct says that it might be possible to store some kind of |
How would that validation look like. Are we talking about tsoa related validations here?
You can still do that. There just won't be a name for it. If there are errors you won't find the type name anywhere in there, that's more like what TS does, as I outlined here: #429 (comment) I'd say it's reasonable for the error message to say 'hey, this is not a string' over 'hey, this is not a Word' given that's exactly what TypeScript would do. If you are using type aliases to create names you are "abusing" tsoa to do something TypeScript would not. |
(Sorry for my late response, English is not my first language so it took quite a while to properly formulate my thoughts on this, I know it looks long but please bear with me [TL;DR included])
No I'm using ajv with json-schemas (automatically generated by ts-json-schema-generator, check out this issue if you're interested). Sorry, I should've mentioned that immediately.
This is exactly my concern. To properly explain why I'll have to give some additional information, so please bear with me. (TL;DR at the bottom) One of the issues present in the "auto-generated json-schema community" (see the issue linked above) is that in some implementations type aliases are "lost" (as far as I can tell in the same way you're proposing here). This is a problem for '3' reasons:
So it makes sense to keep the aliases for json-schemas, but that's of course not what we're discussing here. The first reason (and the reason why I told this 'backstory') is that the "human-readable" issue applies to TSOA too. Of course on a much smaller scale (there's no "constraint-bloat"), but it's still very helpful to read generated routes with the alias names because it provides a form of self-documentation on the required constraints. The second (and way more important) reason is that I want to link my routes to one of the auto-generated json-schemas (which will then verifiy my constraints). I can't do this if I don't know what alias (aka set of constraints) was used to define the route. As far as I know there's no workaround for this other than not using type aliases, which unfortunately isn't possible in a lot of cases. TL;DR: self-documentation and support for more complex validation requirements, in my case by linking routes to json-schemas which have additional constraints attached to them
The internal representation is of course completely up to TSOA, and your proposal definitely sounds like a welcome improvement to me.
I'm not sure what kind of error message you mean, but if you mean the default
I'm not sure what you mean by 'abuse' here, as far as I know it's commonplace to use type aliases for documentation purposes. Again I'm not asking you to support every possible use-case possible, I'm just asking you to carefully consider this. If it's not reasonably possible to keep track of aliases (which would actually surprise me) and it allows for much greater improvements we should of course go in that direction (even if it means I won't be able to use TSOA anymore). I also thought some more about a possible solution. Wouldn't an |
Yes, that's what I was referring to.
That's pretty much what I'm proposing.
Yes, but you should not rely on type aliases to create a name for you. Which is what you are doing when you are expecting it to $ref (and therefore $ref to a name that TS would not have created).
I see your concerns with this idea and I will check if there is a way to mitigate some of the issues you presented. Unfortunately,
I consider the content of the routes file internal though, I think you don't from what I am reading. |
If a user of tsoa is concerned with bloat then they don’t have to use type aliases. |
I'm not sure why it matters how the typescript compiler exactly handles type aliases. We shouldn't try to make stuff do things that they obviously weren't designed for, but saving an aliased name doesn't sound too far fetched to me. (This is all assuming it's reasonably possible to support this "feature")
As far as I remember it worked just fine for me. It's been months since I've touched that project though (I'm working on TSOA right now as "preparation" and to reduce the forks I'm using in production) so I might remember wrong.
I have absolutely no idea how the Swagger/OpenAPI format works so I can't help you with that.
There isn't a reason why they have to, it was just an implementation detail (one could say an unfortunate design choice). The implementation I linked is able to properly preserve aliases without issues (that I know of).
I don't think so indeed, mostly because I'm using router generation for both server and client using custom templates, meaning that it's a direct public interface for me. In another way: I consider the information passed to the template (included or custom) to not be internal (because it's used an manipulated by users).
I can't tell if you mean TSOA is bloated or that concerned users shouldn't use type aliases 😅 |
To clarify: This should work technically fine for most cases. I'm not sure if we'd want to do that for very dynamic stuff, for example, mapped and conditional types or very highly generic types. |
I'm not very familiar with all the technical details, but I guess I ran into something that could be related to this. We have a lot of different object types (e.g. user, house, etc...). Every object has an object id, which is basically a string, but to distinguish between the different ids, and let typescript know what kind of ID i passed in, we are using following "type" for our ids:
e.g.
Alright, so far so good, but now the swagger file does not have the _id as a string, but as an "empty" object instead. It should be a string though... but preferable annotated / commented with the type of id that is required. this is what I get:
right now I use a regex to replace all this strings with "type: string". e.g. it becomes
It seems to work fine, but it's definitly a hack ;) Would the "type alisa shoud be aliases" solve this issue? Or would you recommend some other appraoch to tackle this in a "unhackier" way? Thanks, Regards |
Yes and no. |
I thought about this issue and while I think it's perfectly reasonable to "inline" type aliases, there are valid concerns and probably some missed opportunities I'd like to point out:
Is it more intuitive to expect a named entity here? Yes, especially since OpenAPI supports this. Also, @HoldYourWaffle raised an interesting point I hadn't had in mind initially:
I think it would be nice to compose meaningful types like /**
* This is a description of a special string property
*
* @example "asde"
* @minLength 3
* @maxLength 20
* @pattern ^[a-zA-Z]+$
*/
type SpecialString: string; to be reused throughout your application. @dgreene1 @lukeautry @HoldYourWaffle What do you think? This is a very powerful pattern that requires a lot more things happening internally though. This may be worth it, but I don't think I can spare sufficient time to add this on my own, so if this is something we should pursue I'd be very happy to get any support possible. Is there maybe a way to work on this on a special branch so everyone can contribute? |
I'd be okay with that approach, but honestly I don't use type aliases enough to have a personal investment in this kind of feature.
So in order for me to "get invested," I'd need to see some tsoa users write in to share why better alias support helps them get work accomplished. If the community really wants it then I would definitely jump in. |
Glad to hear that. I think is still a relevant topic because nearly all of the "modern" TS convenience types are type aliases of mapped, conditional or some other types. So I'd really like to get this "right".
If I could get help with specs, code review, and docs from anyone that'd really really help me out. Edit: Issues that need a proper type alias impl: #469, #372, #204, #151 (mapped type needed) |
Yea, don't forget #210 which actually has a bounty prize on it.
Yea, I think if we have a spec that verifies I can help with the specs if/when the time comes. |
Just to clarify: The bare alias implementation won't make those work, but they are a necessary precondition for them to work. We still need a PR that properly parses these (MappedType)Nodes in the AST, but we can't even get to that point if the alias node already won't work. So first we have to address type aliases to tsoa compatible types first (in a way that also works out well with future node types). |
So if I understand correctly, you want to keep the alias references to allow the 'meaningful types' you mentioned? I'm very tired so I'm sorry if I'm missing something obvious here... |
No, please read again. when you are not tired. |
After reading it again and scanning #485 I still don't think I understand. It looks to me like your saving the reference, just in a different format with extra handling. |
What are "alias references" in your mind and what do you mean by "saving the reference"? E: And I generate a seperate validation model for each type alias. |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days |
@HoldYourWaffle @dgreene1 or @WoH Can anyone TLDR this thing? |
TL;Dr: Type aliases are proper references to a OpenAPI component / Swagger definition and merged in the 3.0 branch which is in beta and will be released once all issues in the 3.0 backlog are addressed. Please refer to the Project tracker. |
Tl;Dr: Treat type aliases like symlinks, not like references (models/classes).
From the Typescript handbook on interfaces vs. type aliases:
TSOA currently supports a very narrow set of type aliases: Interface aliasing and Intersections of Interfaces/Classes (where it collects the properties of all members).
Given #400, I would like to make aliases exactly what they are, convenient pointers to other types (unions, intersections, literals etc.) and treat them more or less like as a symlink.
However, this would break some swagger component/definition names (In my mind, the new representation is better, that's why I would prefer not to change it):
#/components/schemas/Namespace_InnerNamespace_TestModel
would become
#/components/schemas/Namespace.InnerNamespace.TestModel
(OpenAPI3, Swagger is similar)
Furthermore, there would no longer be a definition/component for the alias, the content would be inlined.
Thoughts?
The text was updated successfully, but these errors were encountered: