簡體   English   中英

使用 typescript 擴展 nextJS 默認類型

[英]extending nextJS default types with typescript

目前我正在這樣做

路由器.d.ts

import { useRouter } from 'next/router'

declare global {
  type TRouter = ReturnType<typeof useRouter> & {
    query: {
      ticketNumber: string
    }
  }
}

並像這樣使用它:

const { query } = useRouter() as TRouter

我嘗試避免as並使用我的自定義類型擴展 nextJS 類型是

下一個環境.d.ts

/// <reference types="next" />
/// <reference types="next/types/global" />

import * as router from 'next/router'

declare module 'next/router' {
  function useRouter(): ReturnType<typeof router.useRouter> & {
    query: {
      ticketNumber: string
    }
  }

  export { useRouter }
}

但這似乎完全破壞了模塊next/router的類型..

對於模塊擴充,您需要擴展默認類型的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 的類型為function useRouter(): NextRouter

NextRouter 定義為

type NextRouter = BaseRouter & Pick<Router, "push" | "replace" | "reload" | "back" | "prefetch" | "beforePopState" | "events" | "isFallback" | "isReady" | "isPreview">

因此,您可以擴展BaseRouter

type BaseRouter = {
    route: string;
    pathname: string;
    query: ParsedUrlQuery;
    asPath: string;
    basePath: string;
    locale?: string;
    locales?: string[];
    defaultLocale?: string;
    domainLocales?: DomainLocales;
    isLocaleDomain: boolean;
}

在您調用 useRouter() 時定義

或者

您可以擴展 class Router ,實現 BaseRouter,這將允許您有條件地選擇您正在合並的類型,同時不損害默認路由器的完整性

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;
        };
    };
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM