結論
readonlyではない型注釈をした変数に、readonlyなオブジェクトを代入するとプロパティの値の変更ができてしまう。
但し、Object.freeze()でオブジェクトを作成した場合は実行時エラーになる。
オブジェクトを定数として扱うという用途で考えるとas constで十分その要件は満たせると思う。
次回は型注釈の仕組みについて調べたい。
理解を深める為、自分で検証してみました。
参考になる記事を書いてくださった方々に感謝です!
前提
1.以下3つのパターンを使って検証します。
- Readonly
- as const
- Object.freeze()
2.代入方法
- readonlyではない型注釈(type annotation; 型アノテーション)した変数に代入
- スプレッドオペレーター
- Object.assign()
- Object.create()
- JSON.parse(JSON.stringify())
3.代入先のオブジェクトの確認内容
プロパティの値の書き換えのみとします。理由は以下です。
- プロパティの追加はTypeScriptだとコンパイルエラーになる
- プロパティがreadonlyならプロパティの変更は不可能なので、削除と値の書き換えが可能かという結果は同じ
- プロパティの列挙可否は今回の観点としていない。
Readonly
Readonly
type ObjType = {
name: string;
o: { hoge: string }
}
type ReadonlyObjType = Readonly<ObjType>;
const obj: ReadonlyObjType = {
name: "Taisei Yamane",
o: { hoge: "fuga" }
};
obj.o.hoge = "piyo";
obj.name = "";
//Cannot assign to 'name' because it is a read-only property.
const copyObj: ObjType = obj;
copyObj.name = "";
copyObj.o.hoge = "piyo";
const copyObj2 = { ...obj };
copyObj2.name = "";
copyObj2.o.hoge = "piyo";
const copyObj3 = Object.assign({}, obj);
copyObj3.name = "";
//Cannot assign to 'name' because it is a read-only property.ts(2540)
copyObj3.o.hoge = "piyo";
type ObjType = {
name: string;
o: { hoge: string }
}
type ReadonlyObjType = Readonly<ObjType>;
const obj: ReadonlyObjType = {
name: "Taisei Yamane",
o: { hoge: "fuga" }
};
obj.o.hoge = "piyo";
obj.name = "";
//Cannot assign to 'name' because it is a read-only property.
const copyObj: ObjType = obj;
copyObj.name = "";
copyObj.o.hoge = "piyo";
const copyObj2 = { ...obj };
copyObj2.name = "";
copyObj2.o.hoge = "piyo";
const copyObj3 = Object.assign({}, obj);
copyObj3.name = "";
//Cannot assign to 'name' because it is a read-only property.ts(2540)
copyObj3.o.hoge = "piyo";
const copyObj4 = Object.create(obj)
copyObj4.name = "";
copyObj4.o.hoge = "piyo";
const copyObj5 = JSON.parse(JSON.stringify(obj))
copyObj5.name = "";
copyObj5.o.hoge = "piyo";
Object.defineProperty(obj, 'name', {
value: '',
});
as const
as const
type ObjType = {
name: string;
o: { hoge: string }
}
const obj = {
name: "Taisei Yamane",
o:{hoge:"fuga"}
} as const;
obj.o.hoge = "piyo";
//Cannot assign to 'name' because it is a read-only property.
obj.name = "";
//Cannot assign to 'name' because it is a read-only property.
const copyObj:ObjType = obj;
copyObj.name = "";
copyObj.o.hoge = "piyo";
const copyObj2 = {...obj};
copyObj2.name = "";
//Type '""' is not assignable to type '"Taisei Yamane"'.
copyObj2.o.hoge = "piyo";
//Cannot assign to 'hoge' because it is a read-only property.
const copyObj3 = Object.assign({},obj);
copyObj3.name = "";
//Cannot assign to 'name' because it is a read-only property.
copyObj3.o.hoge = "piyo";
//Cannot assign to 'hoge' because it is a read-only property.
const copyObj4 = Object.create(obj)
copyObj4.name = "";
copyObj4.o.hoge = "piyo";
const copyObj5 = JSON.parse(JSON.stringify(obj))
copyObj5.name = "";
copyObj5.o.hoge = "piyo";
Object.defineProperty(obj, 'name', {
value: '',
});
Object.freeze()
Object.freeze()
type ObjType = {
name: string;
o: { hoge: string }
}
const obj = Object.freeze({
name: "Taisei Yamane",
o: { hoge: "fuga" }
});
obj.o.hoge = "piyo";
obj.name = "";
//Cannot assign to 'name' because it is a read-only property.
const copyObj: ObjType = obj;
copyObj.name = "";
copyObj.o.hoge = "piyo";
//実行時エラー
const copyObj2 = { ...obj };
copyObj2.name = "";
//Type '""' is not assignable to type '"Taisei Yamane"'.
copyObj2.o.hoge = "piyo";
const copyObj3 = Object.assign({}, obj);
copyObj3.name = "";
//Cannot assign to 'name' because it is a read-only property.
copyObj3.o.hoge = "piyo";
const copyObj4 = Object.create(obj)
copyObj4.name = "";
copyObj4.o.hoge = "piyo";
//実行時エラー
const copyObj5 = JSON.parse(JSON.stringify(obj))
copyObj5.name = "";
copyObj5.o.hoge = "piyo";
Object.defineProperty(obj, 'name', {
value: '',
});
//実行時エラー
参考)
宣伝させてください!