TL;DR
このページでは、TypeScript の重要な要素の一つである「型ガード」について詳しく解説します。型ガードが何であるか、それがどのように動作し、そして何故それが役立つのか、具体的なソースコードを通じて一緒に学んでいきましょう。
開発環境 | バージョン |
---|---|
Next.js | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
「型ガード」 とは?
型ガードとは、TypeScript で使われる特別な機能で、ある変数が特定の型であることを確認するために使用されます。JavaScript は動的に型が変わる言語なので、一つの変数が異なる型の値を保持する可能性があります。しかし、TypeScript を使うと、コンパイル時に型のエラーを検出できます。それが型ガードの役割です。
型ガードの基本的な形式は以下の通りです。
if (typeof variable === 'type') {
// variable is guaranteed to be 'type' within this block
}
これが型ガードの基本的な考え方で、このif
ブロック内ではvariable
はtype
として扱われます。
使い所
型ガードは、以下のようなシチュエーションで有効に利用できます。
異なる型を持つ可能性がある変数の取り扱い
TypeScript では、異なる型を持つ変数を安全に扱うために、型ガードを使用することがよくあります。たとえば、ある関数が文字列または数値を返す可能性がある場合、その関数の戻り値を適切に処理するには、戻り値がどの型であるかを判断する必要があります。型ガードを使用すると、このような場合にコードの安全性を保証することができます。
ユーザー定義型の確認
複雑な型やユーザー定義の型を扱う場合、そのオブジェクトが特定の型を持つことを保証するために型ガードを使用することができます。この場合、型ガードはオブジェクトが必要なプロパティを持つことを確認し、型安全性を保証します。
API から返されるデータの取り扱い
外部 API からデータを取得する際、返されるデータの形式が確定していない場合もあります。型ガードを使用すると、API から返されるデータが予期した形式を持つことを確認し、データを安全に操作することができます。
コンポーネントのプロップスの型判定
React のコンポーネントでは、プロップスの型を判定するために型ガードを使用することがあります。これにより、異なるプロップスに応じて異なる動作をコンポーネントが実行することができます。
これらのケースは、型ガードが有効に利用できる例です。その他の多くのシチュエーションでも、型ガードはコードの安全性と可読性を向上させ、バグの発生を防ぐ強力なツールとなります。
Next.js で、型ガードを実装
それでは、具体的なコードを見てみましょう。Next.js と TypeScript を用いた型ガードの例を紹介します。
pages/index.tsx
import { NextPage } from 'next'
type Props = {
data: string | number
}
const IndexPage: NextPage<Props> = ({ data }) => {
if (typeof data === 'string') {
// data is guaranteed to be a string here
return <div>{data.toUpperCase()}</div>
} else {
// data is guaranteed to be a number here
return <div>{data * 10}</div>
}
}
export default IndexPage
このコードは Next.js のページコンポーネントで、型ガードを使用してdata
が文字列型か数値型かを確認しています。if
ブロック内では、data
は文字列として扱われ、そのため.toUpperCase()
メソッドを安全に使用できます。一方、else
ブロックでは、data
は数値として扱われ、そのため数値の演算を行うことができます。
型ガードを実装
さらに進んだ型ガードの実装を見ていきましょう。TypeScript ではユーザー定義の型ガードを作ることもできます。これにより、より複雑な型の検査が可能になります。
type User = {
name: string
age: number
}
function isUser(obj: any): obj is User {
return obj && typeof obj.name === 'string' && typeof obj.age === 'number'
}
const IndexPage: NextPage<Props> = ({ data }) => {
if (isUser(data)) {
// data is guaranteed to be User here
return (
<div>
{data.name} - {data.age}
</div>
)
} else {
// data is not User
return <div>Not a user</div>
}
}
export default IndexPage
ここでは、isUser
という型ガード関数を定義し、data
がUser
型であることを検証しています。これにより、data
がUser
型であると確認された場所では、User
型のプロパティに安全にアクセスすることができます。
Emotion で実装
最後に、Emotion という CSS-in-JS ライブラリを使った実装例を見てみましょう。このライブラリは、スタイルをコンポーネントレベルで管理することを可能にしています。
/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react'
import { NextPage } from 'next'
type Props = {
data: string | number
}
const textStyles = css`
font-size: 18px;
color: blue;
`
const IndexPage: NextPage<Props> = ({ data }) => {
if (typeof data === 'string') {
return <div css={textStyles}>{data.toUpperCase()}</div>
} else {
return <div css={textStyles}>{data * 10}</div>
}
}
export default IndexPage
ここでは、data
の型に基づいて異なるテキストを表示していますが、どちらの場合も同じスタイル(textStyles
)を使用しています。Emotion を使うことで、スタイルを再利用し、コンポーネントの見た目を一貫性を保つことができます。
以上が、Next.js と TypeScript を使って型ガードを活用する方法についての解説です。型ガードは TypeScript の強力な機能で、コードの安全性と予測可能性を高める重要なツールです。