next.js + ts 작업시 NextPage 타입 튜닝하여 store를 사용하자.
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
를 사용하는 등의 추가 작업이 생길경우 다음과 같이 타입선언이 일치하지 않다는 에러를 마주하게 됩니다.
에러를 보면 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 깃헙 이슈에 질문을 올려보았으나 지원하지 않는다는 사실만 다시 확인하게 되었습니다. ㅠㅠ
커스텀 타입을 만들자.
결국 여러 고민 끝에 아에 커스텀페이지 타입을 생성하여 유동적으로 사용하는 방법으로 노선을 변경하였습니다.
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 커스텀 타입 사용
해당 커스텀된 타입으로 사용하여 getInitialProps
영역에서도 성공적으로 store 를 호출할 수 있게 되었습니다.