woolta

next.js + ts 작업시 NextPage 타입 튜닝하여 store를 사용하자.

wooltaUserImgb00032 | React | 2019-09-29

NextPage Type

next.js 와 typeScript 를 통해 작업하던 중 Page 에 존재하는 페이지 영역 컴포넌트를 사용할때 next.js 에서 제공 하는 NextPage 타입을 사용하면 간편하게 Page에 대한 타입을 정의할 수 있습니다. NextPage 타입에 대한 사용방법은 다음과 같습니다.

NextPage 타입을 사용한 Page 컴포넌트 제작

import React from 'react';
import { NextPage } from 'next';

interface PageTypeProps{
}

const PageType: NextPage<PageTypeProps> = ({}) => {

  return (
    <div></div>
  );
};

PageType.getInitialProps = async ({}) => {
  return {};
};

export default PageType;

이런식으로 Next.js 에서 제공하는 타입을 사용해 간편한게 Page 영역 컴포넌트를 작성할 수 있지만 이때 서버사이드 렌더링을 위한 생명주기인 getInitialProps 에서 store를 사용하는 등의 추가 작업이 생길경우 다음과 같이 타입선언이 일치하지 않다는 에러를 마주하게 됩니다.

https://image.woolta.com/3fef5b5107bf211d.png

에러를 보면 NextPageContext 라는 곳에서 store 의 타입이 존재하지 않는다고 합니다. 이를 확인하기 위해 NextPage의 타입선언을 확인해 보도록 하겠습니다.

NextPage Type 선언

export type NextPage<P = {}, IP = P> = {
  (props: P): JSX.Element | null
  defaultProps?: Partial<P>
  displayName?: string
  /**
   * Used for initial page load data population. Data returned from `getInitialProps` is serialized when server rendered.
   * Make sure to return plain `Object` without using `Date`, `Map`, `Set`.
   * @param ctx Context of `page`
   */
  getInitialProps?(ctx: NextPageContext): Promise<IP>
}

NextPage 타입은 다음과 같이 타입을 선언하고 있습니다. 이때 getInitialProps 의 타입이 NextPageContext 로 파라미터만 받고 있음을 알 수 있습니다. 그럼 이제 NextPageContext 의 타입 선언을 확인해 보도록 하겠습니다.

NextPageContext 타입

export interface NextPageContext {
    /**
     * Error object if encountered during rendering
     */
    err?: Error & {
        statusCode?: number;
    } | null;
    /**
     * `HTTP` request object.
     */
    req?: IncomingMessage;
    /**
     * `HTTP` response object.
     */
    res?: ServerResponse;
    /**
     * Path section of `URL`.
     */
    pathname: string;
    /**
     * Query string section of `URL` parsed as an object.
     */
    query: ParsedUrlQuery;
    /**
     * `String` of the actual path including query.
     */
    asPath?: string;
    /**
     * `Component` the tree of the App to use if needing to render separately
     */
    AppTree: AppType;
}

다음과 같이 기본 Next에 대한 타입은 전부 선언이 되어 있으나 서버렌더링 상태의 유무를 확인하는 isServer 나 서버사이드 부분에서 store를 통한 작업이 필요할때 해당 타입등을 확장하여 사용할수 없는 구조임을 알 수 있습니다.

확장타입을 지원하지 않는다..

혹시 store를 포함하거나 타입을 추가할수 있는 기능이 지원되는지 궁금해 Next.js 깃헙 이슈에 질문을 올려보았으나 지원하지 않는다는 사실만 다시 확인하게 되었습니다. ㅠㅠ

https://image.woolta.com/3fe78958c3fbe0f9.png

커스텀 타입을 만들자.

결국 여러 고민 끝에 아에 커스텀페이지 타입을 생성하여 유동적으로 사용하는 방법으로 노선을 변경하였습니다.

NextPage 커스텀 타입 선언

import { IncomingMessage, ServerResponse } from 'http';
import { ParsedUrlQuery } from "querystring";
import { AppType } from 'next-server/dist/lib/utils';

export type NextPageCustom<P = {}, IP = P> = {
  (props: P): JSX.Element | null
  defaultProps?: Partial<P>
  displayName?: string
  `?(ctx: nextPageProps): Promise<IP>
}

interface nextPageProps {
  /**
   * Error object if encountered during rendering
   */
  err?: Error & {
    statusCode?: number;
  } | null;
  /**
   * `HTTP` request object.
   */
  req?: IncomingMessage;
  /**
   * `HTTP` response object.
   */
  res?: ServerResponse;
  /**
   * Path section of `URL`.
   */
  pathname: string;
  /**
   * Query string section of `URL` parsed as an object.
   */
  query: ParsedUrlQuery;
  /**
   * `String` of the actual path including query.
   */
  asPath?: string;
  /**
   * `Component` the tree of the App to use if needing to render separately
   */
  AppTree: AppType;

  // 커스텀 항목 추가
  store: any;
  isServer: boolean;
}

위의 코드처럼 다른 선언부는 공용으로 사용하니 그대로 사용하고 하단부에 프로젝트에서 추가로 정의가 필요한 부분만 타입을 추가하여 사용하였습니다.

NextPage 커스텀 타입 사용

https://image.woolta.com/3fd9ab489047149c.png

해당 커스텀된 타입으로 사용하여 getInitialProps 영역에서도 성공적으로 store 를 호출할 수 있게 되었습니다.

Copyright © 2018 woolta.com

gommpo111@gmail.com