Skip to content

Commit 4d600f5

Browse files
committed
Implement alternate fix via ServerBuild type
1 parent 56149e6 commit 4d600f5

File tree

4 files changed

+24
-20
lines changed

4 files changed

+24
-20
lines changed

.changeset/tiny-gifts-wash.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
"@react-router/dev": patch
2+
"react-router": patch
33
---
44

5-
Update generated types for `virtual:react-router/server-build` to ensure compatibility with TypeScript's `exactOptionalPropertyTypes` option
5+
Update `ServerBuild` type to ensure compatibility with TypeScript's `exactOptionalPropertyTypes` option

integration/typegen-test.ts

-1
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,6 @@ test.describe("typegen", () => {
490490
expect(proc.status).toBe(0);
491491
});
492492

493-
494493
test("works with tsconfig 'exactOptionalPropertyTypes' set to 'true'", async () => {
495494
const cwd = await createProject({
496495
"vite.config.ts": viteConfig,

packages/react-router-dev/typegen/index.ts

+12-13
Original file line numberDiff line numberDiff line change
@@ -152,18 +152,17 @@ function register(ctx: Context) {
152152

153153
const virtual = ts`
154154
declare module "virtual:react-router/server-build" {
155-
import type { ServerBuild } from "react-router";
156-
// Whilst this uses the CommonJS 'export =' syntax, which is technically not
157-
// ESM-compliant, it is intentionally implemented this way to properly support
158-
// optional properties in the ServerBuild type.
159-
//
160-
// TypeScript's type system does not provide an elegant solution for defining
161-
// optional exports at the module level in ESM syntax, so this approach offers
162-
// the most accurate type definitions for maintainability.
163-
//
164-
// This ensures all properties of ServerBuild, including optional ones, are
165-
// properly type-checked when using this module.
166-
const serverBuild: ServerBuild;
167-
export = serverBuild;
155+
import type { ServerBuild } from "react-router"; import { ServerBuild } from "react-router";
156+
export const assets: ServerBuild["assets"];
157+
export const assetsBuildDirectory: ServerBuild["assetsBuildDirectory"];
158+
export const basename: ServerBuild["basename"];
159+
export const entry: ServerBuild["entry"];
160+
export const future: ServerBuild["future"];
161+
export const isSpaMode: ServerBuild["isSpaMode"];
162+
export const prerender: ServerBuild["prerender"];
163+
export const publicPath: ServerBuild["publicPath"];
164+
export const routes: ServerBuild["routes"];
165+
export const ssr: ServerBuild["ssr"];
166+
export const unstable_getCriticalCss: ServerBuild["unstable_getCriticalCss"];
168167
}
169168
`;

packages/react-router/lib/server-runtime/build.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,20 @@ export interface ServerBuild {
2424
};
2525
routes: ServerRouteManifest;
2626
assets: AssetsManifest;
27-
basename?: string;
27+
// `| undefined` is required to ensure compatibility with TypeScript's
28+
// `exactOptionalPropertyTypes` option
29+
basename?: string | undefined;
2830
publicPath: string;
2931
assetsBuildDirectory: string;
3032
future: FutureConfig;
3133
ssr: boolean;
32-
unstable_getCriticalCss?: (args: {
33-
pathname: string;
34-
}) => OptionalCriticalCss | Promise<OptionalCriticalCss>;
34+
unstable_getCriticalCss?:
35+
| ((args: {
36+
pathname: string;
37+
}) => OptionalCriticalCss | Promise<OptionalCriticalCss>)
38+
// `| undefined` is required to ensure compatibility with TypeScript's
39+
// `exactOptionalPropertyTypes` option
40+
| undefined;
3541
/**
3642
* @deprecated This is now done via a custom header during prerendering
3743
*/

0 commit comments

Comments
 (0)