Mark incoming state as readonly

zikaeroh created

Change summary

frontend/package.json          |  1 
frontend/src/protocol/index.ts | 39 ++++++++++++++++++++---------------
frontend/yarn.lock             |  5 ++++
3 files changed, 28 insertions(+), 17 deletions(-)

Detailed changes

frontend/package.json 🔗

@@ -25,6 +25,7 @@
         "react-hook-form": "^5.6.3",
         "react-scripts": "^3.4.1",
         "react-use-websocket": "^2.0.1",
+        "ts-essentials": "^6.0.5",
         "typeface-roboto": "^0.0.75",
         "typescript": "^3.9.2",
         "uuid": "^8.0.0"

frontend/src/protocol/index.ts 🔗

@@ -1,17 +1,9 @@
 import myzod, { Infer } from 'myzod';
+import { DeepReadonly } from 'ts-essentials';
 
 // See protocol.go.
 
-export type RoomResponse = Infer<typeof RoomResponse>;
-export const RoomResponse = myzod.object({
-    id: myzod.string().optional().nullable(),
-    error: myzod.string().optional().nullable(),
-});
-
-export type TimeResponse = Infer<typeof TimeResponse>;
-export const TimeResponse = myzod.object({
-    time: myzod.date(),
-});
+// Messages sent from client to server.
 
 export type WordPack = Infer<typeof WordPack>;
 const WordPack = myzod.object({
@@ -83,7 +75,20 @@ export const ClientNote = myzod
         ])
     );
 
-export type StateTile = Infer<typeof StateTile>;
+// Messages sent from server to client.
+
+export type RoomResponse = DeepReadonly<Infer<typeof RoomResponse>>;
+export const RoomResponse = myzod.object({
+    id: myzod.string().optional().nullable(),
+    error: myzod.string().optional().nullable(),
+});
+
+export type TimeResponse = DeepReadonly<Infer<typeof TimeResponse>>;
+export const TimeResponse = myzod.object({
+    time: myzod.date(),
+});
+
+export type StateTile = DeepReadonly<Infer<typeof StateTile>>;
 const StateTile = myzod.object({
     word: myzod.string(),
     revealed: myzod.boolean(),
@@ -97,26 +102,26 @@ const StateTile = myzod.object({
         .nullable(),
 });
 
-export type StateBoard = Infer<typeof StateBoard>;
+export type StateBoard = DeepReadonly<Infer<typeof StateBoard>>;
 const StateBoard = myzod.array(myzod.array(StateTile));
 
-export type StatePlayer = Infer<typeof StatePlayer>;
+export type StatePlayer = DeepReadonly<Infer<typeof StatePlayer>>;
 const StatePlayer = myzod.object({
     playerID: myzod.string(),
     nickname: myzod.string(),
     spymaster: myzod.boolean(),
 });
 
-export type StateTeams = Infer<typeof StateTeams>;
+export type StateTeams = DeepReadonly<Infer<typeof StateTeams>>;
 const StateTeams = myzod.array(myzod.array(StatePlayer));
 
-export type StateTimer = Infer<typeof StateTimer>;
+export type StateTimer = DeepReadonly<Infer<typeof StateTimer>>;
 const StateTimer = myzod.object({
     turnTime: myzod.number(),
     turnEnd: myzod.date(),
 });
 
-export type State = Infer<typeof State>;
+export type State = DeepReadonly<Infer<typeof State>>;
 export const State = myzod.object({
     version: myzod.number(),
     teams: StateTeams,
@@ -136,7 +141,7 @@ export const State = myzod.object({
     hideBomb: myzod.boolean(),
 });
 
-export type ServerNote = Infer<typeof ServerNote>;
+export type ServerNote = DeepReadonly<Infer<typeof ServerNote>>;
 export const ServerNote = myzod.union([
     myzod.object({
         method: myzod.literal('state'),

frontend/yarn.lock 🔗

@@ -10531,6 +10531,11 @@ tr46@^1.0.1:
   dependencies:
     punycode "^2.1.0"
 
+ts-essentials@^6.0.5:
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-6.0.5.tgz#dd5b98f73bd56dc94d15dfbc0fbf01da3163eb42"
+  integrity sha512-RSAKlpu+E0DCGY8FsbG92EveRLw2Y+UgK3ksX01w1VaHeG01dKkYo/KtAV4q0qPT6nPbLfyerb2YPVSediP+8g==
+
 ts-pnp@1.1.6:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.6.tgz#389a24396d425a0d3162e96d2b4638900fdc289a"