diff --git a/src/js/bun.lockb b/src/js/bun.lockb
index acdfdd99..75a86944 100644
Binary files a/src/js/bun.lockb and b/src/js/bun.lockb differ
diff --git a/src/js/eslint.config.mjs b/src/js/eslint.config.mjs
index b2592789..6ebe742f 100644
--- a/src/js/eslint.config.mjs
+++ b/src/js/eslint.config.mjs
@@ -1,29 +1,25 @@
-import path from "node:path";
+import { default as eslint } from "@eslint/js";
 import globals from "globals";
-import { fileURLToPath } from "node:url";
-import js from "@eslint/js";
-import { FlatCompat } from "@eslint/eslintrc";
-
-const __filename = fileURLToPath(import.meta.url);
-const __dirname = path.dirname(__filename);
-const compat = new FlatCompat({
-  baseDirectory: __dirname,
-  recommendedConfig: js.configs.recommended,
-  allConfig: js.configs.all,
-});
+import tseslint from "typescript-eslint";
 
 // ESLint config for Preact project
 export default [
-  ...compat.extends("eslint:recommended"),
+  eslint.configs.recommended,
+  ...tseslint.configs.recommended,
+  { ignores: ["**/node_modules/", "**/dist/"] },
   {
     languageOptions: {
       globals: {
         ...globals.browser,
         ...globals.node,
       },
-
       ecmaVersion: "latest",
       sourceType: "module",
     },
+    rules: {
+      "@typescript-eslint/ban-ts-comment": "off",
+      "@typescript-eslint/no-explicit-any": "off",
+      "@typescript-eslint/no-non-null-assertion": "off",
+    },
   },
 ];
diff --git a/src/js/package.json b/src/js/package.json
index 8a78c3f8..4dbb3b6f 100644
--- a/src/js/package.json
+++ b/src/js/package.json
@@ -9,14 +9,15 @@
     "react-dom": "npm:@preact/compat@17.1.2"
   },
   "devDependencies": {
+    "@eslint/js": "^9.29.0",
     "bun-types": "^0.5.0",
     "eslint": "^9.13.0",
-    "eslint-config-preact": "^1.5.0",
-    "prettier": "^3.3.3"
-  },
-  "eslintConfig": {
-    "extends": "preact"
+    "globals": "^16.2.0",
+    "prettier": "^3.3.3",
+    "typescript": "^5.8.3",
+    "typescript-eslint": "^8.34.0"
   },
+  "license": "MIT",
   "scripts": {
     "check": "prettier --check . && eslint",
     "format": "prettier --write . && eslint --fix"
diff --git a/src/js/src/mount.tsx b/src/js/src/mount.tsx
index c69d63e8..9d2e9a3f 100644
--- a/src/js/src/mount.tsx
+++ b/src/js/src/mount.tsx
@@ -14,8 +14,8 @@ export function mountComponent(
   reconnectBackoffMultiplier: number,
 ) {
   // Protocols
-  let httpProtocol = window.location.protocol;
-  let wsProtocol = `ws${httpProtocol === "https:" ? "s" : ""}:`;
+  const httpProtocol = window.location.protocol;
+  const wsProtocol = `ws${httpProtocol === "https:" ? "s" : ""}:`;
 
   // WebSocket route (for Python components)
   let wsOrigin: string;
@@ -41,7 +41,7 @@ export function mountComponent(
   }
 
   // Embed the initial HTTP path into the WebSocket URL
-  let componentUrl = new URL(`${wsOrigin}/${urlPrefix}/${componentPath}`);
+  const componentUrl = new URL(`${wsOrigin}/${urlPrefix}/${componentPath}`);
   componentUrl.searchParams.append("http_pathname", window.location.pathname);
   if (window.location.search) {
     componentUrl.searchParams.append("http_search", window.location.search);
@@ -66,7 +66,7 @@ export function mountComponent(
 
   // Replace the prerender element with the real element on the first layout update
   if (client.prerenderElement) {
-    client.onMessage("layout-update", ({ path, model }) => {
+    client.onMessage("layout-update", () => {
       if (client.prerenderElement && client.mountElement) {
         client.prerenderElement.replaceWith(client.mountElement);
         client.prerenderElement = null;
diff --git a/src/js/src/types.ts b/src/js/src/types.ts
index e3be73d7..ff930df4 100644
--- a/src/js/src/types.ts
+++ b/src/js/src/types.ts
@@ -19,7 +19,7 @@ export type ReactPyDjangoClientProps = {
 };
 
 export interface DjangoFormProps {
-  onSubmitCallback: (data: Object) => void;
+  onSubmitCallback: (data: object) => void;
   formId: string;
 }
 
@@ -27,5 +27,5 @@ export interface HttpRequestProps {
   method: string;
   url: string;
   body: string;
-  callback: (status: Number, response: string) => void;
+  callback: (status: number, response: string) => void;
 }