TL;DR
このページでは、TypeScript の keyof
オペレーターの実装方法について詳しく解説します。一言でいうと keyof
とは、あるオブジェクトのすべてのプロパティ名の型を抽出する TypeScript のオペレーターです。
開発環境 | バージョン |
---|---|
Next.js | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
keyof
オペレーターとは?
keyof
オペレーターは、TypeScript が持つ特別な型演算子の一つで、オブジェクトの全てのプロパティ名(キー)の型を抽出します。これにより、動的なプロパティのアクセスや、特定のオブジェクトが持つプロパティの名前に制限を加えることなどが可能になります。
基本的な使い方を見てみましょう。
type Animal = {
name: string
age: number
}
type AnimalKeys = keyof Animal // "name" | "age"
ここでは、Animal という型のオブジェクトがあり、keyof
を使ってそのプロパティ名の型を AnimalKeys
という型として抽出しています。結果として AnimalKeys
は "name" | "age"
という型になります。これは、AnimalKeys
は "name"
または "age"
の文字列しか受け取ることができないということを意味します。
keyof のメリット
TypeScript の keyof
の主なメリットは以下の通りです:
-
型安全:
keyof
を使うことで、オブジェクトのキーへのアクセスが型安全になります。これにより、存在しないキーへのアクセスや誤った型へのアクセスによるランタイムエラーを防ぐことができます。 -
コードの再利用性:
keyof
を使うことで、オブジェクトのキーに対して一般的な操作を行う関数やコンポーネントを作成することができます。これにより、同じ操作を異なるキーに対して行うためにコードを繰り返すことなく、一つの関数やコンポーネントを再利用できます。 -
コードの可読性と保守性:
keyof
を使うことで、どのキーがアクセス可能かが型として明示的に表現されるため、コードの可読性と保守性が向上します。
さらにシンプルな例を以下に示します:
type Person = {
name: string
age: number
}
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key]
}
let person: Person = { name: 'John Doe', age: 25 }
let personName = getProperty(person, 'name') // personName is of type 'string'
let personAge = getProperty(person, 'age') // personAge is of type 'number'
この例では、getProperty
関数はオブジェクトとそのキーをパラメータとして受け取り、そのキーに対応するプロパティの値を返します。この関数はどのようなオブジェクトとキーでも動作しますが、keyof
のおかげで、存在しないキーを渡そうとするとコンパイルエラーが発生します。これにより、コードの安全性が向上します。
さらに、この関数は引数 key
の型を動的に判断し、それに基づいて戻り値の型を決定します。このため、戻り値を適切に型付けすることができます。このような動的な型付けは、型安全性を保ちながら JavaScript のような柔軟性を得ることができる TypeScript の強力な特性です。
keyof
オペレーターを実装
Next.js で、次に、具体的な Next.js のコードにこの keyof
オペレーターを導入してみましょう。データを取得する API の呼び出しとその結果の表示を行うシンプルなコンポーネントを作成します。
ファイル名:components/AnimalViewer.tsx
import { useEffect, useState } from 'react'
type Animal = {
name: string
age: number
}
type AnimalKeys = keyof Animal
const AnimalViewer = () => {
const [animal, setAnimal] = useState<Animal | null>(null)
const [key, setKey] = useState<AnimalKeys>('name')
useEffect(() => {
fetch('/api/animal')
.then((res) => res.json())
.then((data) => setAnimal(data))
.catch((error) => console.error(error))
}, [])
if (!animal) {
return <div>Loading...</div>
}
return (
<div>
<button onClick={() => setKey('name')}>Show Name</button>
<button onClick={() => setKey('age')}>Show Age</button>
<div>{animal[key]}</div>
</div>
)
}
export default AnimalViewer
このコンポーネントは、まず /api/animal
から動物のデータを取得し、取得したデータは animal
の状態に保存します。データは name
と age
という二つのプロパティを持つオブジェクトです。
また、key
という状態を持ち、これは表示するプロパティの名前を保持します。key
の型は AnimalKeys
として、"name" | "age"
のいずれかの値しか取らないことが保証されています。そのため、animal[key]
という動的なプロパティアクセスが型安全に行えます。
このコンポーネントには二つのボタンがあり、それぞれが key
の状態を "name"
または "age"
に設定します。そして、animal[key]
の値を表示します。これにより、ボタンを押すことで表示されるプロパティが切り替わる、動的な表示が可能になります。
別の活用例:ソート関数の作成
keyof
は他にも様々な場面で活用できます。例えば、オブジェクトの配列を任意のプロパティでソートする関数を作ることができます。
type Student = {
name: string
age: number
grade: number
}
type StudentKeys = keyof Student
const sortStudents = (students: Student[], key: StudentKeys) => {
return students.sort((a, b) => (a[key] > b[key] ? 1 : -1))
}
ここでは、生徒のデータを表す Student
型と、そのプロパティ名の型 StudentKeys
を定義しました。そして、生徒の配列とソートするプロパティの名前を受け取り、そのプロパティでソートした結果を返す関数 sortStudents
を作りました。
こうした型を活用することで、コードの安全性を向上させるとともに、あらゆる場面での汎用性を保つことが可能となります。JavaScript における柔軟性を損なうことなく、型の恩恵を受けられる TypeScript の強力な機能の一つである keyof
について、ここまで学んできました。
以上、Next.js と TypeScript を使って keyof
オペレーターを活用する方法について解説しました。この力強い機能を駆使することで、より安全で再利用可能なコードを書くことができるようになるでしょう。これからも Next.js と TypeScript を使って、効果的なプログラミングを続けていきましょう。