Skip to content

Instantly share code, notes, and snippets.

@dallonf
Created October 27, 2025 22:03
Show Gist options
  • Select an option

  • Save dallonf/29367e4e0375c04ba3b03b65ef70d40b to your computer and use it in GitHub Desktop.

Select an option

Save dallonf/29367e4e0375c04ba3b03b65ef70d40b to your computer and use it in GitHub Desktop.
Binary search of required memory to run TypeScript on a codebase
#!/usr/bin/env node
const { execSync } = require('child_process');
const fs = require('fs');
const path = require('path');
/**
* Tests if TypeScript can run with the given memory amount
* @param {number} memoryMB - Memory in megabytes
* @returns {boolean} - True if successful, false if out of memory
*/
function testMemory(memoryMB) {
console.log(`Testing with ${memoryMB} MB...`);
try {
execSync(`npx tsc --noEmit --incremental false`, {
stdio: 'pipe',
cwd: __dirname,
env: {
PATH: process.env.PATH,
NODE_OPTIONS: `--max-old-space-size=${memoryMB}`,
},
});
console.log(`✓ Success with ${memoryMB} MB`);
return true;
} catch (error) {
const exitCode = error.status;
// Exit codes in the 130s indicate memory issues
if (exitCode == null || (exitCode >= 130 && exitCode < 140)) {
console.log(
`✗ Out of memory with ${memoryMB} MB (exit code: ${exitCode})`,
);
return false;
}
// Other errors might be compilation errors, which we consider as success
// (it compiled enough to find errors)
console.log(
`✓ Completed with ${memoryMB} MB (exit code: ${exitCode}, non-memory error: ${error.output.toString().trim()})`,
);
return true;
}
}
/**
* Find the upper bound by doubling from a known lower bound
*/
function findUpperBound(lowerBound) {
console.log('\n=== Finding upper bound ===');
let current = lowerBound;
while (true) {
current *= 2;
if (testMemory(current)) {
console.log(`Found upper bound: ${current} MB\n`);
return current;
}
}
}
/**
* Find the lower bound by halving from a known upper bound
*/
function findLowerBound(upperBound) {
console.log('\n=== Finding lower bound ===');
let current = upperBound;
while (true) {
current = Math.floor(current / 2);
if (current < 128) {
console.log(`Reached minimum reasonable memory: ${current} MB\n`);
return current;
}
if (!testMemory(current)) {
console.log(`Found lower bound: ${current} MB\n`);
return current;
}
}
}
/**
* Binary search to find the exact point where it starts failing
*/
function binarySearch(lowerBound, upperBound) {
console.log('\n=== Binary search ===');
console.log(`Searching between ${lowerBound} MB and ${upperBound} MB`);
let low = lowerBound;
let high = upperBound;
while (high - low > 32) {
const mid = Math.floor((low + high) / 2);
if (testMemory(mid)) {
// Success means we can try lower
high = mid;
} else {
// Failure means we need more memory
low = mid;
}
}
return { failsAt: low, succeedsAt: high };
}
// Main execution
console.log('=== TypeScript Memory Requirements Test ===\n');
const initialTest = 2048;
console.log(`Starting with initial test of ${initialTest} MB\n`);
const initialResult = testMemory(initialTest);
let lowerBound, upperBound;
if (initialResult) {
// It succeeded, so we need to find the lower bound
upperBound = initialTest;
lowerBound = findLowerBound(upperBound);
} else {
// It failed, so we need to find the upper bound
lowerBound = initialTest;
upperBound = findUpperBound(lowerBound);
}
const result = binarySearch(lowerBound, upperBound);
console.log('\n=== RESULTS ===');
console.log(`TypeScript FAILS at: ${result.failsAt} MB`);
console.log(`TypeScript SUCCEEDS at: ${result.succeedsAt} MB`);
console.log(`\nMinimum required memory: ~${result.succeedsAt} MB`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment