SolvedDefinitelyTyped [@types/next] withRouter in TypeScript

u3u
177

I want to use a decorator to refer to the router, but there is a problem with type checking in TypeScript. (Does not affect its work, only type checking error)

@types/next/router.d.ts

export function withRouter<T extends {}>(
  Component: React.ComponentType<T & { router: SingletonRouter }>
): React.ComponentType<T>;

First of all, I think a little problem in the type definition, I think router property should be optional.
Because router property is injected from withRouter does not require passing this property when I refer to the component.

export function withRouter<T extends {}>(
-  Component: React.ComponentType<T & { router: SingletonRouter }>
+  Component: React.ComponentType<T & { router?: SingletonRouter }>
): React.ComponentType<T>;

There is no problem using function injection

import * as React from 'react'
import { withRouter, SingletonRouter } from 'next/router'

interface Props {
  router?: SingletonRouter
}

class SiderMenu extends React.Component<Props> { }
export default withRouter(SiderMenu)

There was an error using the decorator

import * as React from 'react'
import { withRouter, SingletonRouter } from 'next/router'

interface Props {
  router?: SingletonRouter
}

@withRouter
export default class SiderMenu extends React.Component<Props> { }

TS Error

@withRouter
^^^
[ts]
Unable to resolve signature of class decorator when called as an expression.
  Type 'ComponentClass<Props>' is not assignable to type 'void | typeof SiderMenu'.
    Type 'ComponentClass<Props>' is not assignable to type 'typeof SiderMenu'.
      Type 'Component<Props, ComponentState>' is not assignable to type 'SiderMenu'.
        Types of property 'render' are incompatible.
          Type '() => ReactNode' is not assignable to type '() => Element'.
            Type 'ReactNode' is not assignable to type 'Element'.
              Type 'string' is not assignable to type 'Element'.

@Dru89 @brikou

13 Answers

✔️Accepted Answer

jmca
132

The just-keep-quiet option:

@(withRouter as any)

Other Answers:

Hours of googling led me to this solution:

import { RouteComponentProps, withRouter } from 'react-router-dom'

interface AnythingProps extends Partial<RouteComponentProps> {
  // your props interface
}

@(withRouter as any)
export class Anything extends Component<AnythingProps> {
  // your class
}

Hope it'll help someone :)

It's been a while but I thought I would come back with a better solution:

Create a custom definition file called react-router-dom.d.ts and add the following:

export * from "@types/react-router";

export { RouteComponentProps } from "react-router";

declare module "react-router-dom" {
  export function withRouter<T extends RouteComponentProps<any>>(
    component?: React.ComponentType<T>
  ): any;
}

This should then let you use @withRouter as a decorator without the @(withRouter as any) hack.

More Issues: