Extending NextJS Default Types With Typescript
Currently I'm doing it like this router.d.ts import { useRouter } from 'next/router' declare global { type TRouter = ReturnType & { query: {
Solution 1:
for module augmentation, you'll want to extend the default type of useRouter()
and absorb your custom integration.
Definition of useRouter
/// <reference types="node" />
import React from 'react';
import Router, { NextRouter } from '../next-server/lib/router/router';
declare type SingletonRouterBase = {
router: Router | null;
readyCallbacks: Array<() => any>;
ready(cb: () => any): void;
};
export { Router, NextRouter };
export declare type SingletonRouter = SingletonRouterBase & NextRouter;
declare const _default: SingletonRouter;
export default _default;
export { default as withRouter } from './with-router';
export declare function useRouter(): NextRouter;
export declare const createRouter: (pathname: string, query: import("querystring").ParsedUrlQuery, as: string, __3: {
subscription: (data: import("../next-server/lib/router/router").PrivateRouteInfo, App: React.ComponentType<import("../next-server/lib/router/router").AppProps>, resetScroll: {
x: number;
y: number;
} | null) => Promise<void>;
initialProps: any;
pageLoader: any;
Component: React.ComponentType<{}>;
App: React.ComponentType<import("../next-server/lib/router/router").AppProps>;
wrapApp: (WrapAppComponent: React.ComponentType<import("../next-server/lib/router/router").AppProps>) => any;
err?: Error | undefined;
isFallback: boolean;
locale?: string | undefined;
locales?: string[] | undefined;
defaultLocale?: string | undefined;
domainLocales?: import("../next-server/server/config-shared").DomainLocales | undefined;
isPreview?: boolean | undefined;
}) => Router;
export declare function makePublicRouterInstance(router: Router): NextRouter;
useRouter is of type function useRouter(): NextRouter
NextRouter is defined as
type NextRouter = BaseRouter & Pick<Router, "push" | "replace" | "reload" | "back" | "prefetch" | "beforePopState" | "events" | "isFallback" | "isReady" | "isPreview">
so, you can either extend BaseRouter
type BaseRouter = {
route: string;
pathname: string;
query: ParsedUrlQuery;
asPath: string;
basePath: string;
locale?: string;
locales?: string[];
defaultLocale?: string;
domainLocales?: DomainLocales;
isLocaleDomain: boolean;
}
which is defined any time you call useRouter()
or
you can extend class Router
, implement BaseRouter, which would allow you to conditionally pick the type you are incorporating while not compromising the integrity of the default Router
export default class Router implements BaseRouter {
route: string;
pathname: string;
query: ParsedUrlQuery;
asPath: string;
basePath: string;
/**
* Map of all components loaded in `Router`
*/
components: {
[pathname: string]: PrivateRouteInfo;
};
sdc: {
[asPath: string]: object;
};
sdr: {
[asPath: string]: Promise<object>;
};
sub: Subscription;
clc: ComponentLoadCancel;
pageLoader: any;
_bps: BeforePopStateCallback | undefined;
events: MittEmitter;
_wrapApp: (App: AppComponent) => any;
isSsr: boolean;
isFallback: boolean;
_inFlightRoute?: string;
_shallow?: boolean;
locale?: string;
locales?: string[];
defaultLocale?: string;
domainLocales?: DomainLocales;
isReady: boolean;
isPreview: boolean;
isLocaleDomain: boolean;
private _idx;
static events: MittEmitter;
constructor(pathname: string, query: ParsedUrlQuery, as: string, { initialProps, pageLoader, App, wrapApp, Component, err, subscription, isFallback, locale, locales, defaultLocale, domainLocales, isPreview, }: {
subscription: Subscription;
initialProps: any;
pageLoader: any;
Component: ComponentType;
App: AppComponent;
wrapApp: (WrapAppComponent: AppComponent) => any;
err?: Error;
isFallback: boolean;
locale?: string;
locales?: string[];
defaultLocale?: string;
domainLocales?: DomainLocales;
isPreview?: boolean;
});
onPopState: (e: PopStateEvent) => void;
reload(): void;
/**
* Go back in history
*/
back(): void;
/**
* Performs a `pushState` with arguments
* @param url of the route
* @param as masks `url` for the browser
* @param options object you can define `shallow` and other options
*/
push(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;
/**
* Performs a `replaceState` with arguments
* @param url of the route
* @param as masks `url` for the browser
* @param options object you can define `shallow` and other options
*/
replace(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;
private change;
changeState(method: HistoryMethod, url: string, as: string, options?: TransitionOptions): void;
handleRouteInfoError(err: Error & {
code: any;
cancelled: boolean;
}, pathname: string, query: ParsedUrlQuery, as: string, routeProps: RouteProperties, loadErrorFail?: boolean): Promise<CompletePrivateRouteInfo>;
getRouteInfo(route: string, pathname: string, query: any, as: string, resolvedAs: string, routeProps: RouteProperties): Promise<PrivateRouteInfo>;
set(route: string, pathname: string, query: ParsedUrlQuery, as: string, data: PrivateRouteInfo, resetScroll: {
x: number;
y: number;
} | null): Promise<void>;
/**
* Callback to execute before replacing router state
* @param cb callback to be executed
*/
beforePopState(cb: BeforePopStateCallback): void;
onlyAHashChange(as: string): boolean;
scrollToHash(as: string): void;
urlIsNew(asPath: string): boolean;
/**
* Prefetch page code, you may wait for the data during page rendering.
* This feature only works in production!
* @param url the href of prefetched page
* @param asPath the as path of the prefetched page
*/
prefetch(url: string, asPath?: string, options?: PrefetchOptions): Promise<void>;
fetchComponent(route: string): Promise<GoodPageCache>;
_getData<T>(fn: () => Promise<T>): Promise<T>;
_getStaticData(dataHref: string): Promise<object>;
_getServerData(dataHref: string): Promise<object>;
getInitialProps(Component: ComponentType, ctx: NextPageContext): Promise<any>;
abortComponentLoad(as: string, routeProps: RouteProperties): void;
notify(data: PrivateRouteInfo, resetScroll: {
x: number;
y: number;
} | null): Promise<void>;
}
For example, I extended AppProps here to incorporate a Session
object so that I can call pageProps.session
to inject NextAuth
with a users session object
next.d.ts
import type { NextComponentType, NextPageContext } from 'next';
import type { Session } from 'next-auth';
import type { Router } from 'next/router';
declare module 'next/app' {
type AppProps<P = Record<string, unknown>> = {
Component: NextComponentType<NextPageContext, any, P>;
router: Router;
__N_SSG?: boolean;
__N_SSP?: boolean;
pageProps: P & {
/** Initial session passed in from `getServerSideProps` or `getInitialProps` */
session?: Session;
};
};
}
Post a Comment for "Extending NextJS Default Types With Typescript"