From 908a3d75fc42d3633b8deb6a97fcad133e570308 Mon Sep 17 00:00:00 2001 From: Simon Holmes Date: Wed, 8 Jul 2026 16:16:15 +0100 Subject: [PATCH 1/5] chore(ts): harden TypeScript checking + add Go-native tsgo gate in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pragmatic TS hardening (deps untouched): - tsconfig: enable noImplicitReturns + noUnusedParameters (both strict, near-zero churn). Skipped the high-churn/low-value flags for now (noPropertyAccessFromIndexSignature ~261 errs); noUncheckedIndexedAccess (~234) and exactOptionalPropertyTypes (~89) are left for follow-up PRs. - Broaden `include` to cover plugins' lib/ and components/ (+ top-level plugin files) — previously only backend.ts/app.tsx/panel.tsx entry files were checked, so lib code was only validated transitively. Add an explicit `exclude` for test/spec, build, and .cache so this stays production-focused. - Adopt the Go-native TypeScript preview (@typescript/native-preview / tsgo), pinned exactly, as a second CI typecheck step. It's ~9x faster than tsc and slightly stricter — it caught a real generic-inference hole tsc missed. tsc stays the authoritative gate; tsgo adds fast coverage. New `typecheck:go` script for local use. Fixes surfaced by the above: - lsfg-vk InstallCard: `Select` inferred its generic as `string`, so the layer-version value flowed into a `LayerVersion` handler unchecked. Pin the generic explicitly (`Select`) — genuinely type-safe, no cast. - recomp/lib/state.ts: 6 vestigial `state` params (the helpers now read fresh state via mutateState) flagged by noUnusedParameters — `_`-prefixed. Audit note: the production `any`/suspect-cast surface is small (~51 across ~24 files) and almost entirely legitimate runtime/FFI boundaries (Electrobun CEF imports resolved at runtime, Steam-webhelper patching). The 8 production @ts-ignore are all on runtime-resolved electrobun/* imports. tsc: 0 · tsgo: 0 · eslint: 0 errors · 364 tests pass. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/ci.yml | 7 +++++++ bun.lock | 21 +++++++++++++++++++-- package.json | 2 ++ plugins/lsfg-vk/InstallCard.tsx | 2 +- plugins/recomp/lib/state.ts | 12 ++++++------ tsconfig.json | 19 ++++++++++++++++++- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0facb9fe..1d49a62a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,13 @@ jobs: - name: Typecheck run: bun run typecheck + # Second, faster typecheck with the Go-native compiler (tsgo, + # @typescript/native-preview, pinned exactly). ~9x faster than tsc and + # occasionally stricter — it caught a real generic-inference hole tsc + # missed. tsc above stays the authoritative gate; this adds coverage. + - name: Typecheck (tsgo, Go-native) + run: bun run typecheck:go + - name: ESLint run: bun run lint diff --git a/bun.lock b/bun.lock index c325c0ce..a8be9fa7 100644 --- a/bun.lock +++ b/bun.lock @@ -20,6 +20,7 @@ "@types/bun": "^1.3.10", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", "eslint-plugin-react-hooks": "^5.0.0", @@ -31,7 +32,7 @@ }, "apps/loadout": { "name": "@loadout/loadout-server", - "version": "0.0.1", + "version": "0.3.1", "dependencies": { "@loadout/exec": "workspace:*", "@loadout/steam-cdp": "workspace:*", @@ -43,7 +44,7 @@ }, "apps/loadout-overlay": { "name": "@loadout/loadout-overlay", - "version": "0.1.0", + "version": "0.3.1", "dependencies": { "@loadout/deck-hid": "workspace:*", "@loadout/exec": "workspace:*", @@ -871,6 +872,22 @@ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="], + "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260707.2", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260707.2", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260707.2", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260707.2" }, "bin": { "tsgo": "bin/tsgo" } }, "sha512-oUGp+Rep/hqMhPunyinsALUwSlzHINSxitifPiSaeqoKOKD2OlR9NE3TaPqwsl4NlGslsOSUXI1JotWQzpYCPg=="], + + "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260707.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wny2pgKjGbiZtnOIHVa3tXC1UfDqxNEFzyPGmiqybedG8hipG2Nfp0l5UxbaKCjkLacUpH/W5bP2hBOMVhCOzg=="], + + "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260707.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-Afc7M5zOwo+GpfcYwz5Z8HMB2tPVsui7nNIqEuuFB73MPdVqNn/Wmpe4tP4MRri0AtJnJknoHBaTJ/VDAp/Jhw=="], + + "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260707.2", "", { "os": "linux", "cpu": "arm" }, "sha512-hJm/UOqZTr9FHmR7uNm8VGX4oKtfWk0Jem0zPeJFNC8ckGUfSBueyiEYMZB+XmRc1aG4x1E46y3CplP4CLHvGQ=="], + + "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260707.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-iITBa2WjjTI5N9t5l7Z4KoOSI+2zBlhbvFzsD/f8qX8QoKjz/Y4DPyBDgezYi8nkqjjksbgSOJ3/ykzhwrB9cg=="], + + "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260707.2", "", { "os": "linux", "cpu": "x64" }, "sha512-du0dzi6y97Po5vDNdPJTyyijHCpaS22JLRnKZEJXBDaO9gCIymOv/5QQokFRuOlQm0bWl3i9PF4OVdGP6uAOQA=="], + + "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260707.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-SsAwfhyHJ1akgBc+99z4+hwdbHsdWaKB8EwCNIMA6JfSLMeUjffrYvxu+vfMyxVtOVOz7RrRXRoiDiu4a2sCtg=="], + + "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260707.2", "", { "os": "win32", "cpu": "x64" }, "sha512-DL4u27stv0fo71sVhOzHSwE+YMZsbBijVI+kg5dLDLilSH79WFTJ8RSQ46vJrCMt+Gjlv/JOZP1PuLJDfioYeQ=="], + "@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], diff --git a/package.json b/package.json index 42ddb1b9..4b778bbe 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "restart": "sh scripts/restart-loadout.sh", "release": "sh scripts/release.sh", "typecheck": "tsc --noEmit", + "typecheck:go": "tsgo -p tsconfig.json", "test": "bun run test:backend && bun run test:ui", "test:backend": "bun test test.ts --isolate", "test:ui": "bun test spec.tsx --preload ./test/bun-test-setup.ts --isolate", @@ -66,6 +67,7 @@ "@types/bun": "^1.3.10", "@types/react": "^18.3.0", "@types/react-dom": "^18.3.0", + "@typescript/native-preview": "7.0.0-dev.20260707.2", "eslint": "^9.0.0", "eslint-config-prettier": "^10.0.0", "eslint-plugin-react-hooks": "^5.0.0", diff --git a/plugins/lsfg-vk/InstallCard.tsx b/plugins/lsfg-vk/InstallCard.tsx index 37391a63..4291819e 100644 --- a/plugins/lsfg-vk/InstallCard.tsx +++ b/plugins/lsfg-vk/InstallCard.tsx @@ -109,7 +109,7 @@ export function InstallCard({ Layer version
-