refactor(react-router): support the `exactOptionalPropertyTypes` ts option in `<Link>`
https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes
☁️ Nx Cloud Report
CI is running/has finished running commands for commit 7d892ac8ef96a46995b4fff31481f1cc2b6e927a. As they complete they will appear below. Click to see the status, the terminal output, and the build insights.
📂 See all runs for this CI Pipeline Execution
✅ Successfully ran 2 targets
Sent with 💌 from NxCloud.
More templates
- tanstack-router-react-example-authenticated-routes
- tanstack-router-react-example-basic
- tanstack-router-react-example-basic-default-search-params
- tanstack-router-react-example-basic-file-based
- tanstack-router-react-example-basic-file-based-codesplitting
- tanstack-router-react-example-react-query
- tanstack-router-react-example-basic-react-query-file-based
- tanstack-router-react-example-basic-ssr-file-based
- tanstack-router-react-example-basic-ssr-streaming-file-based
- tanstack-router-react-example-basic-virtual-file-based
- tanstack-router-react-example-basic-virtual-inside-file-based
- tanstack-router-react-example-deferred-data
- tanstack-router-react-example-kitchen-sink
- tanstack-router-react-example-kitchen-sink-react-query
- tanstack-router-react-example-large-file-based
- tanstack-router-react-example-kitchen-sink-react-query-file-based
- tanstack-router-react-example-location-masking
- tanstack-router-react-example-navigation-blocking
- tanstack-router-react-example-quickstart-file-based
- tanstack-router-react-example-quickstart
- tanstack-router-react-example-quickstart-rspack-file-based
- tanstack-router-react-example-quickstart-webpack-file-based
- tanstack-router-react-example-scroll-restoration
- tanstack-router-search-validator-adapters
- tanstack-start-example-basic
- tanstack-start-example-basic-auth
- tanstack-start-example-basic-rsc
- tanstack-start-example-basic-react-query
- tanstack-start-example-convex-trellaux
- tanstack-start-example-clerk-basic
- tanstack-start-example-counter
- tanstack-start-example-supabase-basic
- tanstack-router-react-example-with-framer-motion
- tanstack-router-react-example-with-trpc
- tanstack-start-example-trellaux
- tanstack-router-react-example-with-trpc-react-query
- tanstack-router-react-example-kitchen-sink-file-based
@tanstack/create-router
pnpm add https://pkg.pr.new/@tanstack/create-router@2213
@tanstack/eslint-plugin-router
pnpm add https://pkg.pr.new/@tanstack/eslint-plugin-router@2213
@tanstack/history
pnpm add https://pkg.pr.new/@tanstack/history@2213
@tanstack/react-cross-context
pnpm add https://pkg.pr.new/@tanstack/react-cross-context@2213
@tanstack/react-router-with-query
pnpm add https://pkg.pr.new/@tanstack/react-router-with-query@2213
@tanstack/react-router
pnpm add https://pkg.pr.new/@tanstack/react-router@2213
@tanstack/router-cli
pnpm add https://pkg.pr.new/@tanstack/router-cli@2213
@tanstack/router-arktype-adapter
pnpm add https://pkg.pr.new/@tanstack/router-arktype-adapter@2213
@tanstack/router-generator
pnpm add https://pkg.pr.new/@tanstack/router-generator@2213
@tanstack/router-devtools
pnpm add https://pkg.pr.new/@tanstack/router-devtools@2213
@tanstack/router-plugin
pnpm add https://pkg.pr.new/@tanstack/router-plugin@2213
@tanstack/router-valibot-adapter
pnpm add https://pkg.pr.new/@tanstack/router-valibot-adapter@2213
@tanstack/router-vite-plugin
pnpm add https://pkg.pr.new/@tanstack/router-vite-plugin@2213
@tanstack/router-zod-adapter
pnpm add https://pkg.pr.new/@tanstack/router-zod-adapter@2213
@tanstack/start
pnpm add https://pkg.pr.new/@tanstack/start@2213
@tanstack/start-vite-plugin
pnpm add https://pkg.pr.new/@tanstack/start-vite-plugin@2213
@tanstack/virtual-file-routes
pnpm add https://pkg.pr.new/@tanstack/virtual-file-routes@2213
commit: 7d892ac
CI failures addressed and changes ( https://github.com/TanStack/router/compare/fca21d38300ebdc467fe0a2a218c467314ce1522..3dab3613c557c09f5a76447a01e41af568a2b201 ) force pushed.
do we have runtime tests and type tests for all those situations where you can pass in an explicit undefined?
To clarify, this PR doesn't alter the type definition, but rather makes the existing behavior more explicit (see https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes ).
thanks for clarification.
can you please add the exactOptionalPropertyTypesflag to the root tsconfig.json so we catch this with our type tests?
Setting "exactOptionalPropertyTypes": true in the root tsconfig.json will result in many type-check errors like this:
src/CatchBoundary.tsx:14:6 - error TS2769: No overload matches this call.
Overload 1 of 2, '(props: { getResetKey: () => string | number; children: (props: { error: Error | null; reset: () => void; }) => ReactNode; onCatch?: (error: Error, errorInfo: ErrorInfo) => void; }): CatchBoundaryImpl', gave the following error.
Type '{ getResetKey: () => string | number; onCatch: ((error: Error, errorInfo: ErrorInfo) => void) | undefined; children: ({ error, reset }: { error: Error | null; reset: () => void; }) => string | ... 6 more ... | undefined; }' is not assignable to type 'Readonly<{ getResetKey: () => string | number; children: (props: { error: Error | null; reset: () => void; }) => ReactNode; onCatch?: (error: Error, errorInfo: ErrorInfo) => void; }>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'onCatch' are incompatible.
Type '((error: Error, errorInfo: ErrorInfo) => void) | undefined' is not assignable to type '(error: Error, errorInfo: ErrorInfo) => void'.
Type 'undefined' is not assignable to type '(error: Error, errorInfo: ErrorInfo) => void'.
Overload 2 of 2, '(props: { getResetKey: () => string | number; children: (props: { error: Error | null; reset: () => void; }) => ReactNode; onCatch?: (error: Error, errorInfo: ErrorInfo) => void; }, context: any): CatchBoundaryImpl', gave the following error.
Type '{ getResetKey: () => string | number; onCatch: ((error: Error, errorInfo: ErrorInfo) => void) | undefined; children: ({ error, reset }: { error: Error | null; reset: () => void; }) => string | ... 6 more ... | undefined; }' is not assignable to type 'Readonly<{ getResetKey: () => string | number; children: (props: { error: Error | null; reset: () => void; }) => ReactNode; onCatch?: (error: Error, errorInfo: ErrorInfo) => void; }>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
Types of property 'onCatch' are incompatible.
Type '((error: Error, errorInfo: ErrorInfo) => void) | undefined' is not assignable to type '(error: Error, errorInfo: ErrorInfo) => void'.
Type 'undefined' is not assignable to type '(error: Error, errorInfo: ErrorInfo) => void'.
14 <CatchBoundaryImpl
There are many places outside of link.tsx that implicitly assume x?: T allows undefined, making them incompatible with this flag.
would it make sense to fix all of those issues?
WIP: I am trying to add the flag to packages/react-router/tsconfig.json (changing the root tsconfig.json seems a bit involved).
It seems that https://github.com/TanStack/router/blob/f36f92b459bf0aabbc4d49c1e72c8b2ad6894622/packages/react-router/src/router.ts#L707-L710 may not work well with explicit undefineds, as {...{transformer: 1}, ...{transformer: undefined}} results in {transformer: undefined}.
Sorry, as enabling exactOptionalPropertyTypes turned out to be more complex than I expected, I have rolled back the branch to https://github.com/TanStack/router/pull/2213/commits/7d892ac8ef96a46995b4fff31481f1cc2b6e927a . Since I've already implemented a workaround without this PR, please feel free to close it, although I believe the changes, while not comprehensive, could still be useful in some cases.
Closing this as there's no movement in the requirement for exactOptionalPropertyTypes.