T
TanStack2y ago
passive-yellow

Search params example raises type errors

Following this example: https://tanstack.com/router/v1/docs/guide/search-params#enter-validation--typescript The return value of validate search raises type errors. Specifically:
interface ProductSearch {
page: number
filter: string
sort: 'newest' | 'oldest' | 'price'
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1), // => passes
filter: search.filter || '', // => Type '{}' is not assignable to type 'string'.
sort: search.sort || 'newest', // Type '{}' is not assignable to type 'string'.
}
}
interface ProductSearch {
page: number
filter: string
sort: 'newest' | 'oldest' | 'price'
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1), // => passes
filter: search.filter || '', // => Type '{}' is not assignable to type 'string'.
sort: search.sort || 'newest', // Type '{}' is not assignable to type 'string'.
}
}
I'm currently using the following to fix these errors (using same example as provided)
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price';

type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1),
filter: search.filter as string || '',
sort: search.sort as ProductSearchSortOptions || 'newest',
}
}
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price';

type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1),
filter: search.filter as string || '',
sort: search.sort as ProductSearchSortOptions || 'newest',
}
}
It seems a bit counter intuitive using it this way. Is there a better way to fix these type errors?
Search Params | TanStack Router Docs
Similar to how TanStack Query made handling server-state in your React applications a breeze, TanStack Router aims to unlock the power of URL search params in your applications. Why not just use URLSearchParams?
22 Replies
correct-apricot
correct-apricot2y ago
Ya, you're right that its a bit counter intuitive. I think the example is a bit simplistic to showcase how it would work, but is missing narrowing functions to really appease TypeScript. In the real Examples, zod is used to avoid all of this, but I think the examples were attempting to showcase how you could do it without an external library, but the specificity of values really makes the typing more complex.
sensitive-blue
sensitive-blue2y ago
Can you provide a PR to fix these docs so that they could at least be copied and compile?
correct-apricot
correct-apricot2y ago
@Manuel Schiller definitely could. Any recommendations on making it simple enough to grok and typesafe without making it seem insanely complex? Even adding narrowing could make it seem overly complex. parseSort(sort: string) sort is ProductSearchSortOptions {}
sensitive-blue
sensitive-blue2y ago
hm I would just use the code above, no actual "validation"
correct-apricot
correct-apricot2y ago
Gotcha, so something along the lines of moving sort to just be a string?
type ProductSearch = {
page: number
filter: string
sort: string
}
type ProductSearch = {
page: number
filter: string
sort: string
}
sensitive-blue
sensitive-blue2y ago
you can leave the string union, and just not check if the value is an member of that union so just assert to make TS happy
correct-apricot
correct-apricot2y ago
Good point. Thanks I'll just ask if this is what you mean before I PR it. Think I'm tripping on my TS terminology.
validateSearch: (search: Record<string, unknown>) => {
return {
page: Number(search?.page ?? 1),
filter: search.filter || '',
sort: search.sort || 'newest',
} as ProductSearch
},
validateSearch: (search: Record<string, unknown>) => {
return {
page: Number(search?.page ?? 1),
filter: search.filter || '',
sort: search.sort || 'newest',
} as ProductSearch
},
sensitive-blue
sensitive-blue2y ago
no I would just go with the code above:
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price';

type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1),
filter: search.filter as string || '',
sort: search.sort as ProductSearchSortOptions || 'newest',
}
}
type ProductSearchSortOptions = 'newest' | 'oldest' | 'price';

type ProductSearch = {
page: number
filter: string
sort: ProductSearchSortOptions
}

validateSearch: (search: Record<string, unknown>): ProductSearch => {
return {
page: Number(search?.page ?? 1),
filter: search.filter as string || '',
sort: search.sort as ProductSearchSortOptions || 'newest',
}
}
if you think this is too complex, then remove the sort prop or just add a sentence that it is recommended to use a proper validation library instead of manually coding this stuff
correct-apricot
correct-apricot2y ago
Gotcha! Apologies for the confusion.
passive-yellow
passive-yellowOP2y ago
I could also open a PR for the docs if either of you haven't yet. Currently do not have access to my pc. However, i could check later. I am using zod for all this validation I was simply wondering if there was another way
correct-apricot
correct-apricot2y ago
I plan to. Sorry about that as I got sidetracked. I’ll get that in today.
passive-yellow
passive-yellowOP2y ago
@Eric Chernuka @Manuel Schiller opened a PR at https://github.com/TanStack/router/pull/991 . Could either of you check whether it complies with the contribution guidelines. It's my first time contributing to OS
GitHub
docs: add type assertion to search-params.md by SilentSwaps · Pull ...
Type assertion so it will at least compile.
sensitive-blue
sensitive-blue2y ago
merged! thanks for this
passive-yellow
passive-yellowOP2y ago
Alrighty How do i close this thread lol
sensitive-blue
sensitive-blue2y ago
you can only leave it not close
passive-yellow
passive-yellowOP2y ago
Ah okay, well I don't mind it. Thought maybe i needed to do like !resolved as in TS discord
sensitive-blue
sensitive-blue2y ago
or maybe you can because you created it? hm i am not a discord pro 😄
passive-yellow
passive-yellowOP2y ago
Oh ye I guess I can. However, might as well leave it up. If someone searches for it might be okay for them to check idk
No description
sensitive-blue
sensitive-blue2y ago
close probably does not delete it ... try it
passive-yellow
passive-yellowOP2y ago
You're right, just hides it I guess and re-opens if someone types here
correct-apricot
correct-apricot2y ago
Thanks @Leaked Data. Apologies again, but other priorities got in my way of getting this done.
passive-yellow
passive-yellowOP2y ago
@Eric Chernuka you're fine! Now i learned how to do it:D

Did you find this page helpful?