From dda00f7a4ef371b4292e2cda9f83c96151083efe Mon Sep 17 00:00:00 2001 From: Richard Date: Thu, 29 Feb 2024 22:26:39 -0800 Subject: [PATCH] feat: add sync typescript types --- src/index.d.ts | 48 +++++++++++++++++++++++++++++++++++++++++--- src/sync/client.luau | 8 ++++---- src/sync/server.luau | 12 +++++------ 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/index.d.ts b/src/index.d.ts index 8a11c2c..3e131d2 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -34,8 +34,8 @@ declare namespace Charm { set: never; } - type AtomStates[]> = { - [Key in keyof T]: T[Key] extends Atom ? State : never; + type AtomArrayToStates[]> = { + [Key in keyof Atoms]: Atoms[Key] extends Atom ? State : never; }; function atom(state: State): Atom; @@ -43,7 +43,7 @@ declare namespace Charm { function isAtom(value: unknown): value is Atom; function derive[], Result>( - ...args: [...atoms: Atoms, combiner: (...atoms: AtomStates) => Result] + ...args: [...atoms: Atoms, combiner: (...atoms: AtomArrayToStates) => Result] ): ReadonlyAtom; function subscribe(atom: Atom, callback: (state: State) => void): () => void; @@ -86,4 +86,46 @@ declare namespace Charm { atom: Atom, selector: (state: State) => Result, ): LuaTuple<[state: Result, setState: (state: Result | ((previous: Result) => Result)) => void]>; + + interface None { + readonly __none: "__none"; + } + + type StatePatch = { + readonly [K in keyof States]?: (States[K] extends object ? StatePatch : States[K]) | None; + }; + + type SyncPayload = { type: "set"; data: States } | { type: "patch"; data: StatePatch }; + + interface AtomMap { + readonly [key: string]: Atom; + } + + type AtomMapToStates = { + readonly [Key in keyof Atoms]: Atoms[Key] extends Atom ? State : never; + }; + + interface ClientSyncOptions { + atoms: Atoms; + } + + interface ClientSyncer { + sync(payload: SyncPayload): void; + } + + interface ServerSyncOptions { + atoms: Atoms; + interval?: number; + } + + interface ServerSyncer { + onSync(callback: (player: Player, payload: SyncPayload) => void): () => void; + hydrate(player: Player): void; + } + + namespace sync { + function client(options: ClientSyncOptions): ClientSyncer>; + + function server(options: ServerSyncOptions): ServerSyncer>; + } } diff --git a/src/sync/client.luau b/src/sync/client.luau index ada134d..d651a5c 100644 --- a/src/sync/client.luau +++ b/src/sync/client.luau @@ -7,13 +7,13 @@ type ClientSyncOptions = { atoms: { [string]: Atom }, } -type ClientSync = { - sync: (self: ClientSync, payload: types.SyncPayload) -> (), +type ClientSyncer = { + sync: (self: ClientSyncer, payload: types.SyncPayload) -> (), } -local function client(options: ClientSyncOptions): ClientSync +local function client(options: ClientSyncOptions): ClientSyncer local atoms = options.atoms - local self = {} :: ClientSync + local self = {} :: ClientSyncer function self:sync(payload) for key, state in payload.data do diff --git a/src/sync/server.luau b/src/sync/server.luau index 34af509..55c6ef0 100644 --- a/src/sync/server.luau +++ b/src/sync/server.luau @@ -11,16 +11,16 @@ type ServerSyncOptions = { interval: number?, } -type ServerSync = { - onSync: (self: ServerSync, callback: (player: Player, payload: types.SyncPayload) -> ()) -> () -> (), - flush: (self: ServerSync, player: Player?) -> (), - hydrate: (self: ServerSync, player: Player) -> (), +type ServerSyncer = { + onSync: (self: ServerSyncer, callback: (player: Player, payload: types.SyncPayload) -> ()) -> () -> (), + flush: (self: ServerSyncer, player: Player?) -> (), + hydrate: (self: ServerSyncer, player: Player) -> (), } -local function server(options: ServerSyncOptions): ServerSync +local function server(options: ServerSyncOptions): ServerSyncer local atoms = options.atoms local interval = options.interval or 0 - local self = {} :: ServerSync + local self = {} :: ServerSyncer local sync: (player: Player, payload: types.SyncPayload) -> () local state: {}