From ed40a6c28d4a3df6f9cc196aae06a1cdad962506 Mon Sep 17 00:00:00 2001 From: Justus Perlwitz Date: Fri, 19 Apr 2024 17:39:26 +0900 Subject: [PATCH] Change state to be a tagged-union like type By turning state from simple string literals to full objects, we can add annotations that are specific to one state. Use case: When retrying connections, we could just add a connectionAttempt?: number; property, but then we would have to check if it is undefined or not, and if we are not reconnecting currently and connectionAttempt? is set, does that mean the Sarus client entered an invalid state? By guaranteeing certain properties to only ever be present when the state property has the right kind, we can avoid a whole class of bugs just by relying on the type system. --- src/index.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 585e433..af4fab9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -134,10 +134,25 @@ export default class Sarus { * * connect(), disconnect() are generally called by the user * - * this.reconnect() is called internally when automatic reconnection is - * enabled, but can also be called by the user + * When disconnected by the WebSocket itself (i.e., this.ws.onclose), + * this.reconnect() is called automatically if reconnection is enabled. + * this.reconnect() can also be called by the user, for example if + * this.disconnect() was purposefully called and reconnection is desired. + * + * The current state is specified by the 'kind' property of state + * Each state can have additional data contained in properties other than + * 'kind'. Those properties might be unique to one state, or contained in + * several states. To access a property, it might be necessary to narrow down + * the 'kind' of state. + * + * The initial state is connecting, as a Sarus client tries to connect right + * after the constructor wraps up. */ - state: "connecting" | "connected" | "disconnected" | "closed" = "connecting"; + state: + | { kind: "connecting" } + | { kind: "connected" } + | { kind: "disconnected" } + | { kind: "closed" } = { kind: "connecting" }; constructor(props: SarusClassParams) { // Extract the properties that are passed to the class