TL;DR
このページでは、TypeScript の readonly
の特性について解説しますね。一言でいうと、readonly
は TypeScript の特性で、特定のプロパティや変数が変更されないことを保証します。
開発環境 | バージョン |
---|---|
Next.js | 13.4.4 |
TypeScript | 5.0.4 |
Emotion | 11.11.0 |
React | 18.2.0 |
readonly
とは?
readonly
は TypeScript の特性で、それが付けられたプロパティや変数が再代入できないことを保証します。これにより、不意のデータの変更を防ぎ、バグを未然に防ぐことができます。
基本的な使用方法は次のようになります。
type ReadonlyUser = {
readonly name: string
readonly age: number
}
const user: ReadonlyUser = {
name: 'Alice',
age: 20,
}
// エラー!name は readonly なので変更できません
user.name = 'Bob'
このコードでは、ReadonlyUser
型に readonly
を付けています。その結果、user
の name
と age
を変更することはできません。
この特性は、ある値が一度設定されると変更されないことを明示的に示すのに役立ちます。これにより、他の開発者がそのコードを読んだときに、その値が変更されることなく、安心してその値を使うことができます。
readonly
と配列
readonly
は配列にも使用できます。これにより、配列自体やその要素が変更されないことを保証できます。詳細は次の例をご覧ください。
const numbers: readonly number[] = [1, 2, 3]
// エラー!numbers は readonly なので変更できません
numbers.push(4)
// エラー!numbers[0] は readonly なので変更できません
numbers[0] = 10
このコードでは、numbers
は readonly number[]
型として宣言されています。そのため、numbers
自体を変更したり、その要素を変更したりすることはできません。
この特性は、特に関数の引数として配列を受け取るときに有用です。関数の内部で配列を変更すると、その影響が関数の外部に波及する可能性があるため、配列が変更されないことを保証することで、バグの可能性を減らすことができます。
関数型コンポーネントでの Readonly
以下に、関数型コンポーネントでの Readonly 使用例を示します。この例では、コンポーネントが受け取るプロパティが変更されないように、Readonly を使用しています。
import React from 'react'
type Props = Readonly<{
message: string
}>
const MessageComponent = ({ message }: Props) => {
return <p>{message}</p>
}
上記の例では、MessageComponent
コンポーネントは message
プロパティを受け取り、それを表示します。ここで、Props
の型を Readonly
でラップすることで、受け取った message
プロパティがコンポーネント内部で変更されないことを保証します。
このように、Readonly
を使うことで、コードが安全になり、予期せぬ副作用を防ぐことができますね。
readonly
を使用する
クラスのメンバに 次に、クラスのメンバに readonly
を使用する例を見てみましょう。
class User {
readonly name: string
readonly age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
const user = new User('Alice', 20)
// エラー!name は readonly なので変更できません
user.name = 'Bob'
ここでは、User
クラスのメンバ name
と age
に readonly
を指定しています。そのため、これらの値は初めて設定された後、変更することはできません。
このように、クラスのメンバに readonly
を付けることで、そのメンバが一度設定された後は変更できないことを示すことができます。これは特に、その値がクラスの内部状態を表す場合や、一度設定されるとその後変更されるべきでない場合に有用です。
readonly
とReadonly
の違い
TypeScript では、readonly
とReadonly
は似ていますが、それぞれ異なる場面で使われます。
readonly
は、オブジェクトのプロパティや、クラスのメンバーを読み取り専用にします。これは、その値が一度設定されると、後から変更できないことを意味します。つまり、値の再代入が防がれます。
class ExampleClass {
readonly name: string
constructor(name: string) {
this.name = name
}
}
const instance = new ExampleClass('test')
instance.name = 'anotherTest' // Error! 'name' is a read-only property.
一方で、Readonly
は一種のユーティリティ型で、与えられた型の全てのプロパティをreadonly
にします。これは、オブジェクトのプロパティが再代入できないようにします。
type ReadonlyPerson = Readonly<{ name: string; age: number }>
const person: ReadonlyPerson = { name: 'John', age: 30 }
person.name = 'Jane' // Error! 'name' is a read-only property.
ここで、Readonly
ユーティリティ型はオブジェクト全体を対象にするのに対して、readonly
修飾子は個々のプロパティに対して使用される点が重要な違いです。