TypeScriptで Next.js の配列の型を理解する

TwitterFacebookHatena

TL;DR

React や Next.js における記事データの取得と出力には、基本的に配列が使用されますので、配列の型を理解することは非常に重要です。「配列の型」とは、TypeScript で配列内の要素の型を定義する方法です。

開発環境 バージョン
Next.js 13.4.4
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

「配列の型」の基本

TypeScript では、配列のすべての要素が同じ型を持つことを保証するために、配列の型を指定できます。これを「配列の型」と言います。

JavaScript では配列は動的に型が変更できますが、TypeScript では配列の要素の型を制限することで、予期しないエラーを防ぐことができます。

例えば、数値のみを要素に持つ配列を作りたい場合、以下のように型注釈を行います。

const numbers: number[] = [1, 2, 3, 4, 5]

ここでは、number[]という型注釈を使っています。これは、「number の配列」を表します。よって、この配列numbersには数値以外の要素を追加することはできません。

同様に、文字列のみを要素に持つ配列も作成できます。

const names: string[] = ['Alice', 'Bob', 'Charlie']

このように、TypeScript では配列の型を明示することで、コードの品質を向上させ、エラーを減らすことができます。

複数の型を持つ配列

TypeScript では、配列の要素が複数の型を持つことがあります。これは JavaScript の柔軟性を活かしつつ、それぞれの型を制限することができます。その場合、(type1 | type2)[]のような形で型注釈をします。

const array: (string | number)[] = [1, 'Alice', 2, 'Bob']

このコードは、arrayという配列が、文字列または数値の要素を持つことを表しています。これを「union types(和集合型)」と言います。

型エイリアスを使用した配列の型定義

大規模なプロジェクトでは、同じ配列の型を何度も書くことは避けたいですね。そこで型エイリアスを活用します。

type StringOrNumber = (string | number)[]
const array: StringOrNumber = [1, 'Alice', 2, 'Bob']

ここでは、StringOrNumberという新しい型を定義し、それを配列arrayの型として使用しています。これにより、コードの冗長性を減らし、保守性を向上させることができます。

Array.filter()

配列に対して、条件を満たす要素だけを取り出すためにArray.filter()を使います。このメソッドは新たな配列を生成し、元の配列を変更しないのが特徴です。

type Employee = {
  name: string
  age: number
}

const employees: Employee[] = [
  { name: 'John', age: 34 },
  { name: 'Emma', age: 28 },
  { name: 'Adam', age: 31 },
]

const youngEmployees = employees.filter((employee) => employee.age < 30)
console.log(youngEmployees)
// [ { name: 'Emma', age: 28 } ]

このコードでは、ageが 30 歳未満のEmployeeだけを取り出しています。

Next.js での活用方法

以下に、ブログ投稿のリストを表示するコンポーネントを考えてみます。Next.js(または React)で記事やデータを取得し、それらを出力する際の主要なステップは次の 3 つ。

  • type で、型エイリアスを作る
  • type で、配列型を適用する
  • map で、記事を出力する

型エイリアスを作る

TypeScript では、型エイリアスを使って複雑な型や再利用可能な型を作成することができます。例えば、記事を表すオブジェクトの形状を表すBlogPostのような型エイリアスを作成します。

配列型を適用する

API から取得した記事データは通常、配列として返されます。これらのデータは、作成した型エイリアス(例:BlogPost)を基にした配列型として定義することができます。この場合、BlogPost[]と表記します。

map で記事を出力する

取得した記事データ(配列)は、Array.prototype.mapメソッドを使って、React の要素(記事コンポーネントのリスト)に変換できます。これにより、個々の記事を個別のコンポーネントとして描画することができます。

これらのポイントは Next.js に限らず、React や TypeScript を使ったフロントエンド開発全般で役立つ考え方です。JavaScript/TypeScript で API からデータを取得し、それを使って UI を描画するときによく出くわすパターンの一つです。

それではまず、ブログ投稿の型を定義してみましょう。

type BlogPost = {
  title: string
  content: string
  author: string
}

次に、この型の配列を受け取るBlogPostListコンポーネントを作ります。

type BlogPostListProps = {
  posts: BlogPost[]
}

const BlogPostList = ({ posts }: BlogPostListProps) => (
  <div>
    {posts.map((post, index) => (
      <div key={index}>
        <h2>{post.title}</h2>
        <p>{post.content}</p>
        <p>Written by: {post.author}</p>
      </div>
    ))}
  </div>
)

このようにして、BlogPostListコンポーネントはBlogPostの配列を props として受け取り、それぞれのブログ投稿を表示します。TypeScript の配列型を使うことで、各ブログ投稿が正しい形式であることを保証します。これにより、開発者はコードの正確性に自信を持つことができ、予期しないエラーを防ぐことができます。

それでは、数字やテキストや日付が混在していたら、どのように書けばよいのでしょうか?

TypeScript は様々なデータ型をサポートしています。ブログ投稿がタイトル(文字列)、内容(文字列)、作者(文字列)、日付(Date)、そしてコメント数(数値)を含むように拡張することができます。

それぞれのフィールドに対して適切な型を指定することで、TypeScript はそれぞれのデータが正しい型であることを保証します。

以下に、拡張されたBlogPost型と、それを使用するBlogPostListコンポーネントの例を示します。

type BlogPost = {
  title: string
  content: string
  author: string
  date: Date
  commentCount: number
}

type BlogPostListProps = {
  posts: BlogPost[]
}

const BlogPostList = ({ posts }: BlogPostListProps) => (
  <div>
    {posts.map((post, index) => (
      <div key={index}>
        <h2>{post.title}</h2>
        <p>{post.content}</p>
        <p>Written by: {post.author}</p>
        <p>Posted on: {post.date.toISOString().substring(0, 10)}</p>
        <p>Comments: {post.commentCount}</p>
      </div>
    ))}
  </div>
)

上記の例では、post.date.toISOString().substring(0, 10)を使って日付をyyyy-mm-dd形式の文字列に変換しています。

記事の取得は基本的に配列を使う

Next.js を使用してブログ記事やその他のリスト形式のデータを取得し、描画するときには、通常配列が使われます。API から取得したデータは、通常、配列や配列の中のオブジェクトとして構造化されています。

例えば、Next.js の getStaticProps または getServerSideProps の中で、ブログの記事データを取得するとしましょう。このデータは通常、複数の記事を含む配列として取得され、この配列は各ページのプロップとして渡されます。

export async function getStaticProps() {
  // Fetch data from external API
  const res = await fetch(`https://.../api/posts`)
  const posts = await res.json()

  // Pass data to the page via props
  return { props: { posts } }
}

type BlogPost = {
  title: string;
  content: string;
  author: string;
  date: Date;
  commentCount: number;
};

type BlogPostListProps = {
  posts: BlogPost[];
};

const BlogPostList = ({ posts }: BlogPostListProps) => (
  // Render the blog posts...
);

上記のコードでは、外部 API からブログの投稿データを取得し、これをgetStaticPropsから返されるprops経由でページコンポーネントに渡しています。そして、そのデータを受け取るBlogPostListコンポーネントは、取得した記事データ(posts)を使って記事のリストを描画します。

そのため、Next.js における記事データの取得と出力には、基本的に配列が使用されます。配列は JavaScript と TypeScript の中核的なデータ構造であり、リスト形式のデータを処理する際には非常に有用です。

TypeScriptで Next.js の配列の型を理解する