typescript 如何定义React Router v6加载程序的返回类型?

zfciruhq  于 2023-03-09  发布在  TypeScript
关注(0)|答案(2)|浏览(121)

我在新的react-router-dom中使用加载器,当我在组件中使用useLoaderData钩子时,响应类型是未知的,所以我不能使用它。我不想使用as类型定义,因为我觉得这是一种欺骗,但如果这是唯一的方法,那么,请让我知道:
我的加载器功能:

{
      path: "/reset-password/:resetToken",
      element: <ResetPassword />,
      loader: async ({ params }) => {
        if (!params.resetToken){
          return null
        }
        const fakeTokens = ["abcdef123456", "bingbong", "foobar"]

        // make API call to check if the given token is valid
        const fakeAPICall = (resetToken: string) : Promise<object> => {
          if (fakeTokens.includes(resetToken)){
            return new Promise(resolve => resolve({ success: true }))
          }

          return new Promise(resolve => resolve({ success: false }))
        }
        
        const resp = await fakeAPICall(params.resetToken);

        return resp;
        
      }
},

<ResetPassword />内部:

// this type is "unknown", so I can't access the properties on it
const resetTokenResponse = useLoaderData()
w41d8nur

w41d8nur1#

useLoaderData钩子的返回类型***是***unknown,因此您需要在组件中重新键入它。
参见来源

/**
 * Returns the loader data for the nearest ancestor Route loader
 */
export function useLoaderData(): unknown {
  let state = useDataRouterState(DataRouterStateHook.UseLoaderData);

  let route = React.useContext(RouteContext);
  invariant(route, `useLoaderData must be used inside a RouteContext`);

  let thisRoute = route.matches[route.matches.length - 1];
  invariant(
    thisRoute.route.id,
    `useLoaderData can only be used on routes that contain a unique "id"`
  );

  return state.loaderData[thisRoute.route.id];
}

使用as类型的AFAIK就是您要做的,即

interface ResetTokenResponse {
  success: boolean;
}

...

const resetTokenResponse = useLoaderData() as ResetTokenResponse;

rkue9o1l

rkue9o1l2#

我个人更喜欢将原来的useLoaderData封装在另一个函数中(至少在它不支持泛型时):

export function useDataFromLoader<LoaderFn extends LoaderFunction>(loaderFn: LoaderFn) {
  return useLoaderData() as Awaited<ReturnType<typeof loaderFn>>
}

这个新函数使用您编写的加载器函数来解析其返回类型。
然后,我们可以使用useDataFromLoader(或者你叫它什么),而不是使用原来的useLoaderData,并将你的加载器fn传递给它(这样它就可以计算出它的返回类型):

async function loader() {
  const data = await Promise.resolve({ foo: 'bar' })
  return data
} satisfies LoaderFunction

function Component() {
  const { foo } = useDataFromLoader(loader)
  return <p>foo === 'bar': {foo === 'bar'}</p>
}

而且我还喜欢说我的加载器satisfies是原来的/预期的LoaderFunction,这样我们就可以访问paramsrequest(例如),并避免在路由器中使用它时出现任何类型不匹配的情况。

相关问题