kiliman / remix-typedjson

This package is a replacement for superjson to use in your Remix app. It handles a subset of types that `superjson` supports, but is faster and smaller.
MIT License
435 stars 19 forks source link

useTypedRouteLoaderData() type inference not working #24

Closed andrecasal closed 1 year ago

andrecasal commented 1 year ago

On my root.tsx:

type LoaderData = {
    isLoggedIn: boolean
}

export const loader = async ({ request }: LoaderArgs): Promise<TypedJsonResponse<LoaderData>> => typedjson({ isLoggedIn: await isLoggedIn(request) })

On my navigation:

import { loader as rootLoader } from '~/root'

export const Navigation = () => {
    const { isLoggedIn } = useTypedRouteLoaderData<typeof rootLoader>('root')
            ^^^^^^^^^^ Property 'isLoggedIn' does not exist on type 'LoaderData | undefined'.
    return <p>This is my header</p>
}

Am I doing something wrong? 🤔

kiliman commented 1 year ago

Hmm... I just tried it and saw that the function could return undefined because the routeId may not exist. If you know it will always return a value, then you can add the ! at the end to tell Typescript that you know this has a value.

https://stackblitz.com/edit/remix-run-remix-l7yqqo?file=app%2Froutes%2Ftest.tsx

andrecasal commented 1 year ago

Hey @kiliman 👋

Ah, thanks for helping me out with this one!

You're importing the loader function as a type: import type { loader as rootLoader } from '~/root';. Wouldn't const { isLoggedIn } = useTypedRouteLoaderData<typeof rootLoader>('root')!; be saying that useTypedRouteLoaderData() is the type of a type (that's meta 😄)?

kiliman commented 1 year ago

I don't think so. I think the import type simply means we only want the type definition. rootLoader is still a function. I pretty much add it because eslint complains

image

andrecasal commented 1 year ago

Wondering why ESLint wasn't complaining like yours, realized ESLint got misconfigured a few commits back 😄 hehe

Alright, I'll close this out. Thanks, @kiliman 👍