如何在 Typescript 中从 react-router-dom 键入 StaticRouterContext?

How to type the StaticRouterContext from react-router-dom in Typescript?

我正在为我的应用做 SSR(仅限机器人)。

<App/> 的渲染可能会导致找不到路线。

我需要检测渲染何时在 NOT_FOUND 路由中结束,以便我可以从我的 express 服务器 return res.sendStatus(404);

我正在关注 this tutorial react-router 的官方文档。

我有一个“捕获所有”路由,它将呈现一个 404 页面并将该信息添加到 staticContext:

AllRoutes.ts

<Route exact path={"*"} render={({ staticContext }) => { 
  if (staticContext) {
    staticContext.statusCode = 404;
  }
  return <Page404/>;
}}/>

Route 组件的 render 属性内的 staticContext 对象推断的类型是:

而且它似乎只有 属性 是可选的 statusCode?: number 属性.

在SERVER端,我是这样做的:

ssrApp.tsx

import App from "@src/App";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router-dom";

// ...

const context = {};  // <<< WHAT TO TYPE THIS VARIABLE ?

const appHtml = renderToString(
  <StaticRouter location={req.url} context={context}>
    <App/>
  </StaticRouter>
);

res.status(context.statusCode || 200).send(appHtml);

<StaticRouter> 组件的 context 属性的类型是 StaticRouterContext:

它接受空的 const context= {}; 属性。但是当我尝试从中访问 statusCode 属性 时它会抱怨。


这里提到的所有类型似乎都来自包 @types/react-router@types/react-router-dom,不太确定是哪个。

@types/react-router/index.d.ts

export interface StaticContext {
    statusCode?: number;
}

export interface RouteComponentProps<
    Params extends { [K in keyof Params]?: string } = {},
    C extends StaticContext = StaticContext,
    S = H.LocationState
> {
    history: H.History<S>;
    location: H.Location<S>;
    match: match<Params>;
    staticContext?: C;
}

如何输入我的 context 对象?到目前为止,我无法从任何地方导入 StaticRouterContextStaticContext

刚刚找到了解决这个问题的方法。

我只安装了以下软件包:

"@types/react-router-dom": "^5.1.5" (AS DEV DEPENDENCY)
"react-router-dom": "^5.2.0"        (AS REGULAR DEPENDENCY)

我无法导入我在问题中提到的类型,因为它们是在 @types/react-router 中定义的,它是 @types/react-router-dom 的内部依赖项,并且它们不会重新从后者导出。

以下是 @types/react-router 中从 @types/react-router-dom 重新导出的类型:

@types/react-router-dom/index.d.ts

我能做的:

我创建了自己的 MY_STATIC_CONTEXT 类型,它需要隐式扩展 @types/react-router 中定义的 StaticContext 类型,该类型在 StaticRouter 和 [=23] 中使用=].

这是 @types/react-router 中的 StaticContext 类型:

export interface StaticContext {
    statusCode?: number;
}

所以我做到了:

type MY_STATIC_CONTEXT = {
  statusCode?: number        // THIS IS SO YOU EXTEND THE ORIGINAL TYPE,
  ROUTE_NOT_FOUND: boolean   // THIS IS MY CUSTOM PROP
}

现在,这是可能的:

ON_CLIENT - AllRoutes.ts

一个简单的类型声明允许我更新我的自定义道具 ROUTE_NOT_FOUND

<Route exact path={"*"} render={({ staticContext }) => { 
  if (staticContext) {
    (staticContext as MY_STATIC_CONTEXT).statusCode = 404; 
    (staticContext as MY_STATIC_CONTEXT).ROUTE_NOT_FOUND = true;
  }
  return <Error404/>;
}}/>

ON_SERVER - ssrApp.tsx

const context: MY_STATIC_CONTEXT = {
  ROUTE_NOT_FOUND: false
};

const appHtml = renderToString(
  <StaticRouter location={req.url} context={context}>
      <App/>
  </StaticRouter>
));

if (context.ROUTE_NOT_FOUND) {
  // DO SOMETHING
}

res.status(context.statusCode || 200).send(appHtml);