TypeScript brings static typing to JavaScript, but debugging TypeScript in Firefox DevTools requires some extra knowledge. Source maps are the key — they let Firefox show your original .ts files even though the browser runs compiled .js. This guide covers setup, debugging patterns, and TypeScript-specific tooling.
How Source Maps Work
When TypeScript compiles to JavaScript, it can generate a .map file:
myfile.ts → myfile.js + myfile.js.map The .map file tells Firefox DevTools: "line 42 in myfile.js corresponds to line 38 in myfile.ts."
Firefox then shows your original TypeScript in the debugger, not the compiled output.
tsconfig.json for Debugging
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "sourceMap": true, "inlineSources": true, "outDir": "./dist", "rootDir": "./src" } } Key flags:
-
"sourceMap": true— generates.mapfiles alongside.js -
"inlineSources": true— embeds source content in the map (works even if original files aren't served) -
"inlineSourceMap": true— embeds the map inside the JS file (one file, easier for dev)
Setting Up Firefox DevTools for TypeScript
- Open DevTools → Settings (F1)
- Ensure "Enable Source Maps" is checked (it is by default)
- Open the Debugger tab
- Your
.tsfiles appear in the file tree under the source map group
// src/counter.ts interface Counter { count: number; increment(): void; reset(): void; } function createCounter(initial = 0): Counter { let count = initial; return { get count() { return count; }, increment() { count++; }, reset() { count = initial; } }; } const counter = createCounter(10); counter.increment(); // Set breakpoint here in DevTools console.log(counter.count); // 11 Set a breakpoint on counter.increment() — Firefox pauses and shows you counter.ts, not the compiled output.
TypeScript Type Errors in the Console
TypeScript errors are compile-time, not runtime. But type errors can manifest as runtime issues:
// TypeScript (compile error, but compiles with --noEmitOnError false): function greet(name: string): string { return "Hello, " + name; } // If called with wrong type at runtime: greet(42 as any); // No TS error but you passed a number Firefox DevTools console shows the runtime result ("Hello, 42"), not a type error. TypeScript's job is done at compile time.
For runtime type checking, use:
function greet(name: unknown): string { if (typeof name !== 'string') { throw new TypeError(`Expected string, got ${typeof name}`); } return "Hello, " + name; } Now Firefox shows TypeError: Expected string, got number with the full stack trace.
Inspecting TypeScript Types in the Console
The console doesn't know TypeScript types at runtime — types are erased during compilation. But you can use typeof and structured inspection:
// In TypeScript source interface User { id: number; name: string; roles: string[]; } const user: User = { id: 1, name: 'Alice', roles: ['admin', 'user'] }; window.__debugUser = user; // Expose for console inspection In Firefox console:
// Types are gone, but structure remains typeof __debugUser // "object" Object.keys(__debugUser) // ["id", "name", "roles"] __debugUser instanceof Object // true TypeScript with Firefox WebExtensions
Firefox extensions benefit from TypeScript — catch errors before publishing to AMO:
npm install --save-dev typescript @types/firefox-webext-browser tsconfig.json for Firefox extension:
{ "compilerOptions": { "target": "ES2017", "lib": ["ES2017"], "strict": true, "sourceMap": true, "types": ["firefox-webext-browser"] } } // background.ts browser.tabs.onUpdated.addListener((tabId, changeInfo, tab) => { // Types are inferred! tabId: number, changeInfo: browser.tabs.TabChangeInfo, etc. if (changeInfo.status === 'complete' && tab.url) { console.log('Tab loaded:', tab.url); } }); // TypeScript catches this at compile time: browser.tabs.query({ actve: true }); // Error: 'actve' is not assignable Debugging TypeScript with Vite
Vite is the most common bundler for TypeScript web apps, and it works well with Firefox:
// vite.config.ts import { defineConfig } from 'vite'; export default defineConfig({ build: { sourcemap: true, // Enable source maps in production build }, }); In development, Vite serves source maps automatically. Firefox DevTools shows your .ts files directly.
TypeScript Declaration Files
When using third-party libraries without TypeScript support, you can add types:
// types/mylib.d.ts declare module 'mylib' { export function doThing(value: string): number; export const VERSION: string; } These don't affect the compiled output, but TypeScript (and your IDE) will understand the types.
Practical TypeScript Patterns for Firefox Apps
// Custom error types class NetworkError extends Error { constructor( message: string, public readonly status: number, public readonly url: string ) { super(message); this.name = 'NetworkError'; } } // Type-safe event emitter type EventMap = { 'data': { id: number; value: string }; 'error': Error; 'close': void; }; class TypedEmitter<T extends Record<string, unknown>> { private listeners = new Map<keyof T, Set<(data: T[keyof T]) => void>>(); on<K extends keyof T>(event: K, listener: (data: T[K]) => void): void { if (!this.listeners.has(event)) this.listeners.set(event, new Set()); this.listeners.get(event)!.add(listener as any); } emit<K extends keyof T>(event: K, data: T[K]): void { this.listeners.get(event)?.forEach(fn => fn(data)); } } const emitter = new TypedEmitter<EventMap>(); emitter.on('data', ({ id, value }) => console.log(id, value)); // fully typed TypeScript + Firefox DevTools: Performance
TypeScript compilation adds a build step. For fastest development iteration:
- Use
tsc --watchor your bundler's watch mode - Enable Firefox DevTools "Enable browser toolbox" for extension debugging
- Use
about:debugging#/runtime/this-firefoxto load and reload extensions without restarting Firefox - Check the Browser Console (
Ctrl+Shift+J) for extension background script errors
TypeScript's compile step catches a whole class of bugs before they reach the browser — pair it with Firefox DevTools for a solid development workflow.
