woolta

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

wooltaUserImgReact | 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 를 호출할 수 있게 되었습니다.