Closed2
[TypeScript] readonly の不要論
tl;dr
readonly 自体は有用性が高いんだけど、使い勝手が微妙なので割り切って入れない選択をしてもいいのでは、という考え方。
背景
いままでreadonly を設定してこなかったので積極的に使おうかなと思って調べた。
利用箇所としては、関数の引数で配列orオブジェクトを受け取るときに破壊的な変更をさせたくないのでreadonlyを設定する。例えばsortとかを関数内部で使っていて、気付いたら配列を破壊してることもあるので。
const accending = (
- list: number[]
+ list : readonly number[]
): number => {
- return list.sort((a, b) => a-b);
+ return [...list].sort((a, b) => a-b);
}
readonly の問題点
TSのreadonlyの問題点としてざっとこれらがある。
- mutable first な設計
- TSはデフォルトでmutableになっているが、逆であってほしい。いまからの変更は現実的ではないのはわかるがせめてcompiler に configを導入してほしい
- Readonly everything by default · Issue #42357 · microsoft/TypeScript · GitHub
- Immutable-By-Default Flags · Issue #32758 · microsoft/TypeScript · GitHub
- GitHub - tc39/proposal-record-tuple: ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!
- readonly 宣言が冗長
- Rustだと
let
/let mut
と完結だが、TSだとconst readonly
/const
となって冗長。readonlyってすべてに書くのはちょっとコード量が長過ぎる。 - また必要に応じて
Readonly<T>
である必要もある
- Rustだと
- readonly 宣言がnestに対応してない
- デフォルトでnestに対応していないので、自前で
DeepReadonly<T>
を作って使わないといけない。 - しかも、
DeepReadonly<T>
であるべきところでReadonly<T>
を使ってしまいそう。これの回避としてデータ構造の内部詳細を意識して型をつけないといけない。漏れをなくすならすべて常にDeepReadonly<T>
にすべきで、必要な場所のみをreadonly
を抜くのがいいがコード冗長さに拍車がかかる。 - playground
- デフォルトでnestに対応していないので、自前で
- readonly が完璧に動作しないことがある
- Object.assign 使うとreadonlyなのに破壊できる。readonlyとは何だったのか。
- TypeScriptのreadonlyプロパティを使いこなす - Qiita
- satisfies と併用できない?(TODO)
- readonly を使う場所は関数の引数であるケースがメインなので、変数宣言をするときに使うsatisfies とは関係ないが、ただふと「この2つをあわせて使えるのか?」がちょっと気になった
代替
TODO: linterとか?
pros/cons
デメリット
- コードがとてつもなく冗長になる
- readonly を設定しても破壊できるコードがありえるので100%の担保にならない
メリット
- 関数のシグネチャから(100%ではないが)破壊的変更がないことがわかる
- 誤って破壊的変更を入れてしまっていたらTS compiler が検知してくれる
結論
readonlyを入れることでより堅牢になる点は間違いないが、使い勝手がものすごく悪いデメリットを考えると脳死で必ず使うべきでもないようにも感じた。
得られるメリットもあるがコードの冗長性などのデメリットを考えると、チームの状況に応じて「意図的にreadonlyは積極的に使わない」という運用
readonly自体がまだコミュニティとして力がそこまで入ってないのでは?と感じて、というのも、Object.assign でreadonlyなのに破壊できたり、immutable-by-default flag みたいなどう見ても有益な設定がなかったりしたので。
感想
TS の言語設計の敗北なのか、負債で仕方がないのか、将来に解決する事案なのか判断がつかないがとりあえず「やっぱRustってすげーよな」って改めて思った。
こっちに書き直した。ほぼ原文と変わらず。
このスクラップは2022/11/13にクローズされました