ここでは、JavaScript で記述されているファイルを TypeScript に変える方法を記述します。
スターターで生成された JavaScript ファイルを順次 TypeScript に変換してゆきます。
流れとしては、以下になります。
変換は以下のように行います。
index.js から index.tsx に変更します。
React をファンクションコンポーネントで構成することにし、型情報を付け加えます。
const IndexPage = () => (
<Layout>
<SEO title="Home" />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)
export default IndexPage
上記で言えば、引数のないファンクションコンポーネントなので、React.FC を使用します。
必要な変更はこれだけです。
変更箇所をハイライトします。
const IndexPage: React.FC = () => ( <Layout>
<SEO title="Home" />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
);
export default IndexPage;
エラーを見ながら import 先を順次変換していきます。
ここでのポイントは以下になります。
もとのコードは以下です。
変更が必要な箇所をハイライトします。
const Layout = ({ children }) => {const data = useStaticQuery(graphql` query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`)
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0px 1.0875rem 1.45rem`,
paddingTop: 0,
}}
>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</div>
</>
)
}
Layout.propTypes = {children: PropTypes.node.isRequired,}
export default Layout
これを変換してゆきます。
引数には children が存在し、propTypes を参考にしながらこの型を ReactNode とします。
interface Prop {
children: React.ReactNode;
}
const Layout の部分は以下のように変更します。
- const Layout = ({ children }) => {
+ const Layout: React.FC<Prop> = ({ children }) => {
propTypes は使用しないので、削除します。
- Layout.propTypes = {
- children: PropTypes.node.isRequired,
- }
クエリ結果のデータについての型定義を行います。 実際にアクセスしているのが以下の部分です。
data.site.siteMetadata.title
上記から以下のように定義します。
interface QueryType {
site: {
siteMetadata : {
title: string;
}
}
}
interface Prop {
children: React.ReactNode;
}
interface QueryType {
site: {
siteMetadata : {
title: string;
}
}
}
const Layout: React.FC<Prop> = ({ children }) => {
const data: QueryType = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`);
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `0px 1.0875rem 1.45rem`,
paddingTop: 0,
}}
>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</div>
</>
);
};
export default Layout;
layout.js 同じようにして header.js も変換します。 siteTitle の型は、propTypes を参考にして定義します。
今までのやりかたと、ほとんど同じようにして変換します。 QueryType に関しては、以下のようにしました。
interface QueryType {
placeholderImage: {
childImageSharp: {
fluid: FluidObject;
}
}
}
今までのものより少々複雑です。
変換元のファイルは以下のようになっています。
function SEO({ description, lang, meta, title }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
/>
)
}
propTypes 等や上記ソースコードを参考にしながら、型をつけてゆきました。
最終的には以下のようになりました。
interface MetaObject {
name: string;
content: string;
}
interface Prop {
description?: string;
lang?: string;
meta?: MetaObject[];
title: string;
}
interface QueryType {
site: {
siteMetadata: {
title: string;
description: string;
author: string;
}
}
}
const SEO: React.FC<Prop> = ({ description = '', lang = 'en', meta = [], title }) => {
const { site }: QueryType = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
return (
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
meta={[
{
name: `description`,
content: metaDescription,
},
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:card`,
content: `summary`,
},
{
name: `twitter:creator`,
content: site.siteMetadata.author,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(meta)}
/>
);
};
export default SEO;
以下のファイルに関しても同じようにして、変換を行いました。
ここでは、特に新しいことは出てきませんでした。
src 以下の全ての js ファイルを tsx ファイルに変換したら終了です。
今回変換したファイルは、実際には使用しない可能性が高いです。
ですが、流れを掴むために行ってみました。
とりあえず初期のプロジェクト作成に関してはこれで終了です。