本文介绍了使用打字稿扩展 nextJS 默认类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前我是这样做的

router.d.ts

import { useRouter } from 'next/router'

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

并像这样使用它:

const { query } = useRouter() as TRouter

我尝试避免 as 并使用我的自定义类型扩展 nextJS 类型

My attempt to avoid the as and extend nextJS types with my custom types are

next-env.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..

but that just seems to break the types completely for the module next/router..

推荐答案

对于模块扩充,您需要扩展 useRouter() 的默认类型并吸收您的自定义集成.

for module augmentation, you'll want to extend the default type of useRouter() and absorb your custom integration.

useRouter 的定义

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 的类型为 function useRouter(): NextRouter

useRouter is of type function useRouter(): NextRouter

NextRouter 定义为

NextRouter is defined as

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() 时都会定义

which is defined any time you call useRouter()

您可以扩展类 Router,实现 BaseRouter,这将允许您有条件地选择要合并的类型,同时不影响默认路由器的完整性

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

例如,我在这里扩展了 AppProps 以合并一个 Session 对象,以便我可以调用 pageProps.session 向用户注入 NextAuth会话对象

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

这篇关于使用打字稿扩展 nextJS 默认类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-13 05:40