From 709165bab0a6ae91f99b3bb5be0a99c3c5890ded Mon Sep 17 00:00:00 2001 From: Szymon Nowakowski Date: Fri, 28 Mar 2025 22:06:09 +0100 Subject: [PATCH] Minor refactors --- packages/backend/src/model.ts | 6 ++-- packages/common/package.json | 3 ++ packages/common/src/Brand.ts | 35 ----------------------- packages/common/src/Function.ts | 4 --- packages/common/src/Types.ts | 1 - packages/common/src/index.ts | 2 +- packages/frontend/src/hooks/useLoading.ts | 6 ++-- packages/frontend/src/hooks/useStore.ts | 10 ++++--- packages/frontend/src/routes/Root.tsx | 3 +- pnpm-lock.yaml | 4 +++ 10 files changed, 20 insertions(+), 54 deletions(-) delete mode 100644 packages/common/src/Brand.ts delete mode 100644 packages/common/src/Function.ts delete mode 100644 packages/common/src/Types.ts diff --git a/packages/backend/src/model.ts b/packages/backend/src/model.ts index 82c056a..1dac204 100644 --- a/packages/backend/src/model.ts +++ b/packages/backend/src/model.ts @@ -1,5 +1,5 @@ import * as Common from "common"; -import * as Function from "common/Function"; +import { unsafeCoerce } from "effect"; import { t } from "elysia"; export interface AccessTokenPayload { @@ -24,8 +24,8 @@ export interface IdTokenPayload { } const brandedString = () => t.Transform(t.String()) - .Decode(Function.unsafeCoerce) - .Encode(Function.unsafeCoerce); + .Decode(unsafeCoerce) + .Encode(unsafeCoerce); export const Sha256_Hex = brandedString(); export const AttachmentId = brandedString(); diff --git a/packages/common/package.json b/packages/common/package.json index 1a3f683..0bd1736 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -7,6 +7,9 @@ ".": { "import": "./src/index.ts" }, "./*": { "import": "./src/*.ts" } }, + "dependencies": { + "effect": "catalog:" + }, "devDependencies": { "typescript": "catalog:" } diff --git a/packages/common/src/Brand.ts b/packages/common/src/Brand.ts deleted file mode 100644 index aea6fcb..0000000 --- a/packages/common/src/Brand.ts +++ /dev/null @@ -1,35 +0,0 @@ -import * as Function from "./Function"; -import * as Types from "./Types"; - -declare const BrandTypeId: unique symbol; -export type BrandTypeId = typeof BrandTypeId; - -declare const ConstructorTypeId: unique symbol; -export type ConstructorTypeId = typeof ConstructorTypeId; - -export interface Brand { - readonly [BrandTypeId]: { - readonly [k in K]: K; - }; -} - -export declare namespace Brand { - export interface Constructor> { - readonly [ConstructorTypeId]: ConstructorTypeId; - (args: Brand.Unbranded): A; - } - - export type Unbranded

= P extends infer Q & Brands

? Q : P; - - export type Brands

= P extends Brand - ? Types.UnionToIntersection<{ - [k in keyof P[BrandTypeId]]: k extends string | symbol ? Brand : never - }[keyof P[BrandTypeId]]> - : never; -} - -export type Branded = A & Brand; - -export const nominal = >(): Brand.Constructor => { - return Function.identity as Brand.Constructor; -}; diff --git a/packages/common/src/Function.ts b/packages/common/src/Function.ts deleted file mode 100644 index 8f0bb7a..0000000 --- a/packages/common/src/Function.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const identity = (a: A): A => a; - -// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- unsafe by design -export const unsafeCoerce: (a: A) => B = identity as any; diff --git a/packages/common/src/Types.ts b/packages/common/src/Types.ts deleted file mode 100644 index ac92a80..0000000 --- a/packages/common/src/Types.ts +++ /dev/null @@ -1 +0,0 @@ -export type UnionToIntersection = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 8d4908c..5af7734 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -1,4 +1,4 @@ -import * as Brand from "./Brand"; +import { Brand } from "effect"; export type UUID = Brand.Branded; export const UUID = Brand.nominal(); diff --git a/packages/frontend/src/hooks/useLoading.ts b/packages/frontend/src/hooks/useLoading.ts index 850dbd8..cd06eba 100644 --- a/packages/frontend/src/hooks/useLoading.ts +++ b/packages/frontend/src/hooks/useLoading.ts @@ -1,5 +1,5 @@ import { API_URL_PREFIX } from "@/client"; -import { mapProp, Update, Updater, useStore } from "@/hooks/useStore"; +import { mapProp, Update, Updater } from "@/hooks/useStore"; import { Treaty } from "@elysiajs/eden"; import { Effect, Fiber, pipe } from "effect"; import React, { useCallback, useEffect, useState } from "react"; @@ -45,8 +45,6 @@ export function useLoading>(fn: () => Promise< const navigate = useNavigate(); - const setUser = useStore(state => state.setUser); - const [result, setResult] = useState>(IS_LOADING); useEffect(() => { @@ -82,7 +80,7 @@ export function useLoading>(fn: () => Promise< return () => { cancelled = true; }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, [navigate, setUser, ...deps]); + }, [navigate, ...deps]); return result; } diff --git a/packages/frontend/src/hooks/useStore.ts b/packages/frontend/src/hooks/useStore.ts index b7fb2d1..7bcb1d3 100644 --- a/packages/frontend/src/hooks/useStore.ts +++ b/packages/frontend/src/hooks/useStore.ts @@ -1,5 +1,5 @@ import { UserId } from "common"; -import * as Function from "common/Function"; +import { identity } from "effect"; import { useLayoutEffect, useState } from "react"; export type Update = T | ((prev: T) => T); @@ -19,14 +19,16 @@ export namespace Store { export interface Store { readonly user: Store.User | null; - readonly setUser: Updater; } let store: Store = Object.freeze({ user: null, - setUser: (action) => set(mapProp("user", action)), }); +export function setUser(action: Update) { + set(mapProp("user", action)); +} + // --- STORE IMPLEMENTATION ---------------------------------------------------- class Listener { @@ -64,7 +66,7 @@ function set(action: Partial | ((store: Store) => Partial), replac } } -export function useStore(selector: Selector = Function.identity as Selector): T { +export function useStore(selector: Selector = identity as Selector): T { const [state, setState] = useState(() => selector(store)); diff --git a/packages/frontend/src/routes/Root.tsx b/packages/frontend/src/routes/Root.tsx index 6aaa8b6..c91f73f 100644 --- a/packages/frontend/src/routes/Root.tsx +++ b/packages/frontend/src/routes/Root.tsx @@ -1,7 +1,7 @@ import { API_URL_PREFIX, client } from "@/client"; import { Button, buttonVariants } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; -import { useStore } from "@/hooks/useStore"; +import { setUser, useStore } from "@/hooks/useStore"; import { Settings, User } from "lucide-react"; import { useEffect } from "react"; import { Link, Outlet } from "react-router-dom"; @@ -9,7 +9,6 @@ import { Link, Outlet } from "react-router-dom"; export function Root() { const user = useStore(state => state.user); - const setUser = useStore(state => state.setUser); const init = async () => { if (user !== null) return; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a281d7..4319acd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -167,6 +167,10 @@ importers: version: 5.7.2 packages/common: + dependencies: + effect: + specifier: 'catalog:' + version: 3.11.4 devDependencies: typescript: specifier: 'catalog:'