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.
Top comments (0)