😊

Next.js の InferGetStaticPropsType が便利

2021/01/04に公開
1

Next.jsのサンプルリポジトリを眺めていたらInferGetStaticPropsTypeというものを見つけました。これを使うと、getStaticPropsでreturnされた値をもとに、Pageに渡されるPropsの型を類推してくれます。

↓ ドキュメントはこちら

https://nextjs.org/docs/basic-features/data-fetching#typescript-use-getstaticprops

これまではこんな感じで書いていた

これまではPropsの型宣言を自分で書いていました。

import { GetStaticProps } from 'next';

// 👇
type Props = { posts: Post[] };

export const getStaticProps: GetStaticProps<Props> = async () => {
  const { posts } = await getPosts();
  return {
    props: {
      posts,
    },
    revalidate: 1
  };
};

const Page: NextPage<Props> = (props) => { ... }
export default Page;

InferGetStaticPropsTypeを使うと…

InferGetStaticPropsType<typeof getStaticProps>のように書くことで、getStaticProps()の返り値をもとにPageに渡される型を類推してくれます。

import { InferGetStaticPropsType } from 'next';

// 👇
type Props = InferGetStaticPropsType<typeof getStaticProps>;

export const getStaticProps = async () => {
  const { posts } = await getPosts(); // => { posts: Post[] }
  return {
    props: {
      posts,
    },
    revalidate: 1
  };
};

const Page: NextPage<Props> = (props) => { ... }
export default Page;

いつの間にこんなものが使えるようになっていた……?と思い、調べてみるとドキュメントに記載されたのは2020年5月のようです。

getStaticProps() 自体には型アノテーションをつけないこと

Teratailで「InferGetStaticPropsTypeを使ったらany型になってしまった」という投稿を見つけたので、勝手にここで回答しちゃいます。

https://teratail.com/questions/296722

公式ドキュメントを参考にInferGetStaticPropsTypeを使ってみたのですが、コンポーネント内のitemsにマウスホバーするとany型が表示されています。

この質問者の方は以下のようなコードを書いている模様。

うまく類推が効かない例
import { GetStaticProps, InferGetStaticPropsType } from 'next';

export const getStaticProps: GetStaticProps = async () => {
  const items: User[] = sampleUserData;
  return { props: { items } };
};

// ...省略...

うまく類推が効かない理由はexport const getStaticProps: GetStaticProps = ...というようにgetStaticProps()に対してGetStaticPropsのアノテーションをつけてしまっているからだと思われます。: GetStaticPropsを外せばちゃんと類推されるはず。

そうするとgetStaticProps()の引数がanyにならない?

代わりにGetStaticPropsContextを引数にあててあげれば良いですね!

import { InferGetStaticPropsType, GetStaticPropsContext } from 'next';

type Props = InferGetStaticPropsType<typeof getStaticProps>;

export const getStaticProps = async (context: GetStaticPropsContext) => {
  const { query } = context
};

Discussion

hidetaka okamotohidetaka okamoto

以下のように、GetStaticPropsのGenericsにpropsの型を指定してやるとInferGetStaticPropsTypes側でもanyにならない様子でした。

export const getStaticProps: GetStaticProps<{
  items: User[]
}> = async () => {
  const items: User[] = sampleUserData;
  return { props: { items } };
};

ここの指定がない場合、props{[key: string]: any}になるのでInferGetStaticPropsTypesanyになるのだと思います。

export type GetStaticProps<
  P extends { [key: string]: any } = { [key: string]: any },
  Q extends ParsedUrlQuery = ParsedUrlQuery
> = (
  context: GetStaticPropsContext<Q>
) => Promise<GetStaticPropsResult<P>> | GetStaticPropsResult<P>