T
TanStack•2y ago
united-yellow

How do I stop search params from being automatically converted to number?

In validateSearch, a search param that's alphanumeric is coming in as a number if there are no letters in the value. Is this expected? My input validation with Valibot rejects it because of that. I really wouldn't expect the router to do anything with the value before validateSearch runs. For example, using URL the value is parsed as a string, not number.
window.location.href // 'http://localhost:3000?code=123'
new URL(window.location.href).searchParams.get('code') // '123' (string)

export const Route = createFileRoute('/')({
validateSearch(search) {
search.code // 123 (number)
}
})
window.location.href // 'http://localhost:3000?code=123'
new URL(window.location.href).searchParams.get('code') // '123' (string)

export const Route = createFileRoute('/')({
validateSearch(search) {
search.code // 123 (number)
}
})
17 Replies
quickest-silver
quickest-silver•2y ago
can you show a reproduction by forking one of our examples please? I remember having to use z.coerce explicitly because I'm getting in strings for numbers
united-yellow
united-yellowOP•2y ago
Yeah of course, just wanted to check whether this is expected behavior or not first Here's a repro, although using useSearch which gives the same result https://stackblitz.com/edit/github-8tcva3?file=src%2Froutes%2Findex.tsx
quickest-silver
quickest-silver•2y ago
thanks, you're right. Even the input to validateSearchalready has code as number @Manuel Schiller is taht on purpose? Tbh I don't think so. Also, for validateSearch, the input is typed as {}. In the docs, we manually put a type there as Record<string, unknown>. Why isn't that the default?
quickest-silver
quickest-silver•2y ago
aah okay I got it. It seems like our defaultSearch parsing uses qss and that converts strings to numbers, and booleans as well https://github.com/TanStack/router/blob/ee5bb089f2336dc0f411149360f996d04b615ef9/packages/react-router/src/qss.ts#L47-L53
GitHub
router/packages/react-router/src/qss.ts at ee5bb089f2336dc0f4111493...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
quickest-silver
quickest-silver•2y ago
it can be customized: https://tanstack.com/router/latest/docs/framework/react/guide/custom-search-param-serialization#custom-search-param-serialization I think docs aren't fully up to date because it mentions:
By default, TanStack Router parses and serializes your search params automatically using JSON.stringify/JSON.parse
but it does more parsing additionally
Custom Search Param Serialization | TanStack Router React Docs
TODO This portion of documentation is currently under construction By default, TanStack Router parses and serializes your search params automatically using JSON.stringify/JSON.parse. Depending on your needs though, you may want to customize the serialization process.
quickest-silver
quickest-silver•2y ago
I still think that default type should be Record<string, unknown>: https://github.com/TanStack/router/blob/6c1d831b2747222d5cbbbe4b61df3308bd05a09b/packages/react-router/src/route.ts#L114 thoughts @Chris Horobin ?
GitHub
router/packages/react-router/src/route.ts at 6c1d831b2747222d5cbbbe...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
united-yellow
united-yellowOP•2y ago
Yeah I agree on the type. Would be much easier to access properties on it if it was Record<string, unknown>
fair-rose
fair-rose•2y ago
I agree. {} just means anything that's not null or undefined which is not correct likely
united-yellow
united-yellowOP•2y ago
So for the parsing, are the docs wrong or the code? 😅
united-yellow
united-yellowOP•2y ago
When doing this
parseSearch: parseSearchWith(JSON.parse),
stringifySearch: stringifySearchWith(JSON.stringify),
parseSearch: parseSearchWith(JSON.parse),
stringifySearch: stringifySearchWith(JSON.stringify),
I'm getting a really weird result. The search param switches between number and string a couple of times on load.
No description
united-yellow
united-yellowOP•2y ago
I'll see if I can reproduce this in the stackblitz
united-yellow
united-yellowOP•2y ago
Yeah parseSearch/stringifySearch does not seem to help here. It's still number https://stackblitz.com/edit/github-8tcva3-d7fvbp?file=src%2Fmain.tsx
Jakob Norlin
StackBlitz
Router Quickstart File Based Example (forked) - StackBlitz
Run official live example code for Router Quickstart File Based, created by Tanstack on StackBlitz
quickest-silver
quickest-silver•2y ago
GitHub
router/packages/react-router/src/searchParams.ts at 41391cdd4a41ea5...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
quickest-silver
quickest-silver•2y ago
and then the parser is run on every element so it seems like you'll get boolean for true/false, number for number and string for everything else could be a feature 😂 pathParams are different though - they are always a string. Not sure if that difference is a good thing :/
united-yellow
united-yellowOP•2y ago
No honestly I would expect to always get strings back as a default Luckily I tested with a numeric string to start off, but otherwise I would have probably pushed to prod a broken implementation, since we do schema validation in validateSearch which would fail on some values
robust-apricot
robust-apricot•2y ago
@Tanner Linsley do we really want to "pre-parse" search params into "best fitting" types prior to validateSearch? Or should we default to strings?
vicious-gold
vicious-gold•2y ago
Not everyone will put the effort into validation. This is still better than the default experience imo. We have to do some level of pre parsing to go from Record of string,string to JSON Validation relies on json. And there is a difference between storing a string/number/bool in the URL. That difference has just never been formalized before.

Did you find this page helpful?