Skip to content Skip to sidebar Skip to footer

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" />importReactfrom'react';
importRouter, { NextRouter } from'../next-server/lib/router/router';
declaretypeSingletonRouterBase = {
    router: Router | null;
    readyCallbacks: Array<() =>any>;
    ready(cb: () =>any): void;
};
export { Router, NextRouter };
exportdeclaretypeSingletonRouter = SingletonRouterBase & NextRouter;
declareconst_default: SingletonRouter;
exportdefault _default;
export { defaultas withRouter } from'./with-router';
exportdeclarefunctionuseRouter(): NextRouter;
exportdeclareconstcreateRouter: (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;
exportdeclarefunctionmakePublicRouterInstance(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

typeBaseRouter = {
    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

exportdefaultclassRouterimplementsBaseRouter {
    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;
    staticevents: 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

importtype { NextComponentType, NextPageContext } from'next';
importtype { Session } from'next-auth';
importtype { Router } from'next/router';
declaremodule'next/app' {
    typeAppProps<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"