diff --git a/app/javascript/entrypoints/application.js b/app/javascript/entrypoints/application.ts
similarity index 81%
rename from app/javascript/entrypoints/application.js
rename to app/javascript/entrypoints/application.ts
index d13388b47..1087b1c4c 100644
--- a/app/javascript/entrypoints/application.js
+++ b/app/javascript/entrypoints/application.ts
@@ -1,5 +1,5 @@
 import './public-path';
-import main from "mastodon/main";
+import main from 'mastodon/main';
 
 import { start } from '../mastodon/common';
 import { loadLocale } from '../mastodon/locales';
@@ -10,6 +10,6 @@ start();
 loadPolyfills()
   .then(loadLocale)
   .then(main)
-  .catch(e => {
+  .catch((e: unknown) => {
     console.error(e);
   });
diff --git a/app/javascript/entrypoints/error.js b/app/javascript/entrypoints/error.ts
similarity index 64%
rename from app/javascript/entrypoints/error.js
rename to app/javascript/entrypoints/error.ts
index 6376dc2f5..db68484f3 100644
--- a/app/javascript/entrypoints/error.js
+++ b/app/javascript/entrypoints/error.ts
@@ -2,7 +2,9 @@ import './public-path';
 import ready from '../mastodon/ready';
 
 ready(() => {
-  const image = document.querySelector('img');
+  const image = document.querySelector<HTMLImageElement>('img');
+
+  if (!image) return;
 
   image.addEventListener('mouseenter', () => {
     image.src = '/oops.gif';
@@ -11,4 +13,6 @@ ready(() => {
   image.addEventListener('mouseleave', () => {
     image.src = '/oops.png';
   });
+}).catch((e: unknown) => {
+  console.error(e);
 });
diff --git a/app/javascript/entrypoints/inert.js b/app/javascript/entrypoints/inert.ts
similarity index 100%
rename from app/javascript/entrypoints/inert.js
rename to app/javascript/entrypoints/inert.ts
diff --git a/app/javascript/entrypoints/mailer.js b/app/javascript/entrypoints/mailer.ts
similarity index 100%
rename from app/javascript/entrypoints/mailer.js
rename to app/javascript/entrypoints/mailer.ts
diff --git a/app/javascript/entrypoints/public-path.js b/app/javascript/entrypoints/public-path.ts
similarity index 69%
rename from app/javascript/entrypoints/public-path.js
rename to app/javascript/entrypoints/public-path.ts
index f4d166a77..ac4b9355b 100644
--- a/app/javascript/entrypoints/public-path.js
+++ b/app/javascript/entrypoints/public-path.ts
@@ -2,7 +2,7 @@
 // to share the same assets regardless of instance configuration.
 // See https://webpack.js.org/guides/public-path/#on-the-fly
 
-function removeOuterSlashes(string) {
+function removeOuterSlashes(string: string) {
   return string.replace(/^\/*/, '').replace(/\/*$/, '');
 }
 
@@ -15,7 +15,9 @@ function formatPublicPath(host = '', path = '') {
   return `${formattedHost}/${formattedPath}/`;
 }
 
-const cdnHost = document.querySelector('meta[name=cdn-host]');
+const cdnHost = document.querySelector<HTMLMetaElement>('meta[name=cdn-host]');
 
-// eslint-disable-next-line no-undef
-__webpack_public_path__ = formatPublicPath(cdnHost ? cdnHost.content : '', process.env.PUBLIC_OUTPUT_PATH);
+__webpack_public_path__ = formatPublicPath(
+  cdnHost ? cdnHost.content : '',
+  process.env.PUBLIC_OUTPUT_PATH,
+);
diff --git a/app/javascript/entrypoints/share.jsx b/app/javascript/entrypoints/share.tsx
similarity index 64%
rename from app/javascript/entrypoints/share.jsx
rename to app/javascript/entrypoints/share.tsx
index 7b5723091..792625085 100644
--- a/app/javascript/entrypoints/share.jsx
+++ b/app/javascript/entrypoints/share.tsx
@@ -2,7 +2,7 @@ import './public-path';
 import { createRoot } from 'react-dom/client';
 
 import { start } from '../mastodon/common';
-import ComposeContainer  from '../mastodon/containers/compose_container';
+import ComposeContainer from '../mastodon/containers/compose_container';
 import { loadPolyfills } from '../mastodon/polyfills';
 import ready from '../mastodon/ready';
 
@@ -16,7 +16,7 @@ function loaded() {
 
     if (!attr) return;
 
-    const props = JSON.parse(attr);
+    const props = JSON.parse(attr) as object;
     const root = createRoot(mountNode);
 
     root.render(<ComposeContainer {...props} />);
@@ -24,9 +24,13 @@ function loaded() {
 }
 
 function main() {
-  ready(loaded);
+  ready(loaded).catch((error: unknown) => {
+    console.error(error);
+  });
 }
 
-loadPolyfills().then(main).catch(error => {
-  console.error(error);
-});
+loadPolyfills()
+  .then(main)
+  .catch((error: unknown) => {
+    console.error(error);
+  });
diff --git a/package.json b/package.json
index 0b5c3484d..24d81ea47 100644
--- a/package.json
+++ b/package.json
@@ -167,6 +167,7 @@
     "@types/redux-immutable": "^4.0.3",
     "@types/requestidlecallback": "^0.3.5",
     "@types/webpack": "^4.41.33",
+    "@types/webpack-env": "^1.18.4",
     "@typescript-eslint/eslint-plugin": "^7.0.0",
     "@typescript-eslint/parser": "^7.0.0",
     "babel-jest": "^29.5.0",
diff --git a/yarn.lock b/yarn.lock
index 0b60c39c9..ffc64ba08 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2766,6 +2766,7 @@ __metadata:
     "@types/redux-immutable": "npm:^4.0.3"
     "@types/requestidlecallback": "npm:^0.3.5"
     "@types/webpack": "npm:^4.41.33"
+    "@types/webpack-env": "npm:^1.18.4"
     "@typescript-eslint/eslint-plugin": "npm:^7.0.0"
     "@typescript-eslint/parser": "npm:^7.0.0"
     arrow-key-navigation: "npm:^1.2.0"
@@ -3990,6 +3991,13 @@ __metadata:
   languageName: node
   linkType: hard
 
+"@types/webpack-env@npm:^1.18.4":
+  version: 1.18.4
+  resolution: "@types/webpack-env@npm:1.18.4"
+  checksum: 10c0/3fa77dbff0ed71685404576b0a1cf74587567fe2ee1cfd11d56d6eefcab7a61e4c9ead0eced264e289d2cf0fc74296dbd55ed6c95774fe0fd6264d156c5a59f0
+  languageName: node
+  linkType: hard
+
 "@types/webpack-sources@npm:*":
   version: 3.2.2
   resolution: "@types/webpack-sources@npm:3.2.2"