GatsbyJS と TypeScript でブログを作成して公開する(4)
~ gatsby-starter-blog を TypeScript で書き換えたときのポイント ~
前回の投稿は環境構築を紹介しましたが、実際に TypeScript に書き換える段になると、以外につまる部分も出てきます。
今回は、筆者が書き換えをおこなった時に気になったポイントを紹介していきます。
最終的なコードの全体像はこちらのリポジトリをご覧ください。
Prerequisites
前回の記事にしたがって以下の環境構築をおこなった前提で進めていきます。
1. VSCode の利用
2. `gatsby-starter-blog`スターターを使用して Gatsby プロジェクトを作成
3. TypeScript の型チェックのための設定
4. ESLint, Prettier の導入
TypeScript に書き換える手順
手順としては、
.js
の拡張子を.tsx
に変更する- 1.でエディターに ESLint のエラーが出るので確認
- GraphQL のクエリに名前がついていなければつける
gatsby develop
コマンドを実行してgatsby-plugin-typegen
に型を自動生成させる- 自動生成された型を使用して
any
になっている部分を消していく - その他 ESLint のエラーを消していく
といった感じでしょうか。
前回の環境構築でエラーはわかりやすくなっているので、
とにかく tsx にしてエラーを出す方針でいきます。
ポイント
実際に書き換えていった際のポイントをご紹介します。
GraphQL のレスポンスの型の生成
方法そのものは前回の記事で紹介していますので省略します。
ここで気になったのは、生成される型情報についてです。
たとえば、src/pages/index.tsx
で
export const pageQuery = graphql`
query BlogIndex {
site {
siteMetadata {
title
description
}
}
}
`;
とした場合に生成される型情報は以下のようになります。
// src/__generated__/gatsby-types.ts
type BlogIndexQuery = {
readonly site: Maybe<{
readonly siteMetadata: Maybe<
Pick<SiteSiteMetadata, "title" | "description">
>;
}>;
};
ここでMaybe<T>
が目につきますが、これはgatsby-types.ts
の上部にこのように定義されています。
type Maybe<T> = T | undefined;
TypeT
とundefined
の Union 型になっています。
よって以下のように、
const BlogIndex: React.FC<PageProps<GatsbyTypes.BlogIndexQuery>> = ({
data,
location,
}) => {
// Optional Chainingが必要になる
const siteTitle = data.site?.siteMetadata?.title || 'Title';
Optional Chaining 演算子?.
、Null 合体演算子??
、論理和演算子||
、Type Guard などが必要になってきます。
変数の末尾に!
をつける Non-Null Assertion 演算子もありますが、
ESLint エラーが出るようにしているのでよほどの理由がなければさけるようにします。
gatsby-plugin-typegen の生成がうまくいかないことがある
これはまだ解決策がわかっていないのですが、
gatsby-plugin-typegen
で型がうまく生成されないことがあります。
gatsby develop
コマンドをやり直したり、
クエリ名を削除して保存、付け直して保存を繰り返していると出来たりできなかったり。
また、差分のチェックなどはしていないようで、
gatsby develop
するたびにsrc/__generated__/gatasby-types.ts
が書き変わってしまいます。
しかも、生成される順番も変わっているようで、ソース管理に入れていると、
ちょっと確認する度に変更有になってしまってかなり鬱陶しい。
冪等性のある処理にはならないものなんでしょうか。。。
SEO.tsx の引数の型
編集前のファイルを確認すると下部にこのような記述があります。
SEO.defaultProps = {
lang: 'en',
meta: [],
description: '',
};
SEO.propTypes = {
description: PropTypes.string,
lang: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
}
PropTypes というのはFlowや TypeScript などで型チェックをおこなわない場合にも、
コンポーネントの props の型チェックをするための React のライブラリです。
PropTypes の詳細はこちらの公式のドキュメントを見ていただくとして、
今回は TypeScript をつかうので props の引数の型は自力で作ってあげる必要があります。
このような感じです。
type Props = {
description?: string;
lang?: string;
meta?: HTMLMetaElement[];
title: string;
};
const SEO: React.FC<Props> = ({ description, lang, meta, title }) => {
/// ...
layout.js を.tsx に変更すると PATH_PREFIX で怒られる
これに対処するには、定義ファイルを作成する必要があります。
// src/global.d.ts
// eslint-disable-next-line no-underscore-dangle
declare const __PATH_PREFIX__: string;
まとめ
少々短いですが、ここで終わりです。
最終的なプロジェクトの全体はこちらのリポジトリをご覧ください。