Breakspec found a bug in Microsoft’s TypeScript compiler
We pointed Breakspec at the TypeScript repository with one rule: the declaration files the compiler writes must be valid TypeScript. It broke that rule after 19 inputs. The bug is public as microsoft/TypeScript#64760, and a fix is under review.
- Rule
- Declaration files the compiler writes must be valid TypeScript.
- Smallest input
export default 1.7976931348623159e308;- Compiler output
declare const _default = Infinity;- Result
- The same compiler rejects that file with error TS1254.
- Also affects
- TypeScript 6.0.3
- Fix
- Written with Claude Code from Breakspec’s fix request, verified by Breakspec, under review.
The bug
A number too large for a double, like 1e400, evaluates to Infinity. When the compiler writes a declaration file for a constant with that value, it writes Infinity as the initializer:
// m.ts
export const a = 1e400;
export const b = -1e400;
export class C {
static readonly e = 1e400;
}
export default 1.7976931348623159e308;// m.d.ts, as the compiler wrote it
export declare const a = Infinity;
export declare const b = -Infinity;
export declare class C {
static readonly e = Infinity;
}
declare const _default = Infinity;
export default _default;The compiler then rejects its own output. Each of those initializers is error TS1254: an ambient constant must be initialized with a string or numeric literal, and Infinity is a name, not a literal. A library that exports a constant like this ships declaration files that fail type-checking for its users, unless they skip checking library types.
It isn’t new
TypeScript 6.0.3 writes the same initializers. We checked in the TypeScript Playground. The bug predates the move to the new compiler written in Go, and no existing TypeScript test covered it.
How Breakspec found it
- We used the repository as it was on its main branch, unchanged.
- We gave it one rule, on
CommandLine, the compiler’s entry point: declaration files the compiler writes are valid TypeScript. The check compiles a program with declarations on, then compiles those declarations with the same compiler. - Breakspec ran the compiler in an isolated sandbox and broke the rule after 19 inputs. The smallest is one line,
export default 1.7976931348623159e308;, just past the largest number a double can hold.
The fix, and how it was checked
Breakspec turned the failure into a fix request, and Claude Code wrote the fix from it: a constant whose value is Infinity or NaN gets the type number instead of an initializer.
// m.d.ts, with the fix
export declare const a: number;
export declare const b: number;
export declare class C {
static readonly e: number;
}
declare const _default: number;
export default _default;- Breakspec replayed the failing input against the fix, then tried 300 fresh inputs. None failed.
- TypeScript’s own Go test suite passes: 64 packages, plus a new compiler test. Without the fix, that test records 6 TS1254 errors.
- References to enum members with these values, like
E.A, were already valid and are left alone. - The pull request says the fix was written with AI assistance, as TypeScript’s contribution guidelines ask, and a person is responsible for it in review.
The recording
The recording mixes live dashboard footage with explanation slides. The dashboard parts were recorded live on the real repository: approving the rules, the run that finds the bug, and the check of the fix. The slides show the fix itself, TypeScript’s test results and the commit. The two long waits are sped up, with an on-screen clock showing the real time.
What this shows
The TypeScript compiler has a large test suite, and it passed. The bug sat where no example test looked, and one rule about what must always be true found it. Breakspec does the same for the code your agents write: it works out what must hold, proves each failure, has your agent fix it and checks the fix.
Join the waitlistTypeScript is a trademark of Microsoft Corporation. Breakspec isn’t affiliated with or endorsed by Microsoft. The issue and pull request are public on GitHub; their status may have changed since this page was written.