-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
feat: Type narrowing on status().send() chains #4761
Conversation
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.
lgtm
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.
Personally, I would against it.
This changes means everyone using schema should provide all possible return.
I would imagine it turns out would be casting any
everywhere for the payload.
This is bad why? Why would you want your schema to be mismatched from what actually happens in your code? |
If someone intentionally describes a schema for the response payload, then it would make sense that they would want this security enforced at the type level. Furthermore, if they don't want to cast as I also think it is important that the schema reflect all possible return types to ensure consistency and if there are several return types, the schema can just have a broader definition. i.e. |
It is bad because how can you send with The next question is you should also consider the
I would say a no on this solution. You are forcing people coding styles just because the types doesn't match. Anyway, it just a personal feeling. I do not block this to land. |
@aadito123 Hi! Cool PR! :) Hey, just have a quick read over the original PR for typed reply types, specifically this comment #3524 (comment). Narrowing on the status code was previously considered, however the generic argument (as implemented in v3/v4) wasn't (at the time) conducive to supporting it (as the type provider implementation was specifically written to match capabilities of the raw generics). The following is the raw generics (as i remember them) server.get<{
Reply: string | number // { should be Reply: { 200: string, 500: number }
}>('/', {
schema: {
response: {
200: { type: 'string' },
500: { type: 'number' }
}
}
}, (_, reply) => { ... }) It would be possible to support narrowing through the type providers, but would be worth considering the @RafaelGSS would be good to revisit this aspect. |
I am not sure if the generic pattern is suitable when a schema is defined. There would need to be some reconciliation to make sure that either the type in the generic is respected in the schema or if the schema is respected by the generic since a type would essentially be defined in two places. However, I totally agree, that without a type provider, the generics would be the way to go. Edit: just wanted to add, the generics could also solve @climba03003 concern about Buffer and stream payloads. |
@aadito123 Hey, Just have a quick review of the implementation below. Note that it's not currently possible to specify status codes on the Generic import Fastify from 'fastify'
const fastify = Fastify()
fastify.get<{
Reply: { // note: this is a requirement for status code narrowing with generics
200: string,
500: number
}
}>('/', (req, res) => {
res.send('') // expect: number | string
res.status(200).send('') // expect: string
res.status(500).send(1) // expect: number
}) I do think both Generic and Type Provider inference should probably work the same here in terms of status code narrowing. However without first updating the The change to update the I'm actually VERY keen to see your PR implemented, but I do think it's important to weigh whether going out with this functionality now is the right call (knowing it may introduce a varying behavior for Generic and Type Provider inference), or whether it's best to wait for the |
@sinclairzx81 I agree that updating the generics with the type providers would be the better move. However, as you mentioned, setting a constraint on the generic to be
This might be a nitpick but I think number is both too wide and too narrow of a type for the key since it would allow invalid status codes and exclude wildcards like '2xx'. I have already written a couple type helpers that might serve us better for the key type. Nonetheless, I do not see my PR becoming an source of conflict for when the fastify/test/types/type-provider.test-d.ts Lines 51 to 66 in d0d3696
|
This reverts commit 0657f9b.
Yeah, I saw the status code mapping, looks good.
Yeah, it's just something to be mindful of more than anything. The original implementation of reply type inference held back on status code narrowing (for the reasons noted above). However, this was back in December 2021 (obviously, a very long time ago). I do still think it's worth considering the Generics side of things (and to put a spotlight on the current Good work! :) |
That is fair. As useful as I find this to be in my own code base, if the team feels it might be better to hold off until the generics are also ready, that is fine. |
You can always jot some notes on #4081 |
Just wanted to chime in and say that the Reply type narrowing was the only thing I considered missing from Fastify. I have been messing around with it the past few days as I've been considering switching from Express to Fastify for work-related projects. The fact that I can define a schema in one place and have it both generate TS types and OAS docs is extremely powerful and time saving, it's just missing the ability to type-check the responses accurately. So to me this is a very welcomed addition. |
Yes, it would be a good addition for type-check to exist. The use-case is more than you though, restricting |
First of all, thank you for the PR, @aadito123! Amazing stuff. |
@fox1t I suppose that is fair. My only concern with it would be that now the schema and the Reply argument may not have matching types, although perhaps some sort of inference magic can make it work. Nonetheless, I think people might end up having to define types twice (once in the generic, and once in the schema) or having to change up their code style a bit to avoid that. I would be happy to work on a PR for the Reply generic if that is an implementation the typescript team can get behind. Personally, I really want the type narrowing, so I don't mind if I change my code a little to do it. |
I don't understand this sentence. Could you rephrase it? |
@fox1t what I meant was that if the Typescript team is okay with using the Reply generic, and will merge the PR (assuming implementation is good), then I am ready to work on it. Basically, I don't want to make a PR for it and realize that it could still be a breaking change. |
Oh! Thanks for clarifying! @fastify/typescript, do we agree on this? My vote is yes. Let’s do it. |
This pull request has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. |
Added type narrowing on chained
.status(xxx).send(xxx)
calls.Closes #4755
Checklist
npm run test
andnpm run benchmark
and the Code of conduct