The config follows the compiler options Bun's documentation recommends, adapted for .js files: checkJs instead of allowJs, and none of the options that only matter for .ts files. The files below are one project, checked with TypeScript 5.9 when this site is built.
Install
@types/bun declares the Bun global and Bun's modules; per the Bun documentation, install it with bun add -d @types/bun. TypeScript provides tsc. Install both as development dependencies (with npm, npm install --save-dev typescript @types/bun):
bun add -d typescript @types/bun jsconfig.json
module: "preserve" with moduleResolution: "bundler" matches how Bun resolves imports, lib: ["esnext"] with types: ["bun"] gives Bun's APIs and no DOM, and moduleDetection: "force" treats every file as a module, as Bun does. Bun's recommended config also turns on noUncheckedIndexedAccess, noImplicitOverride and noFallthroughCasesInSwitch; add them if you want the stricter level.
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "preserve",
"moduleResolution": "bundler",
"target": "esnext",
"lib": ["esnext"],
"moduleDetection": "force",
"types": ["bun"],
"skipLibCheck": true
},
"include": ["src/**/*.js"]
} npm scripts
Run them with bun run lint or npm run lint; either way it is tsc that checks.
{
"type": "module",
"scripts": {
"lint": "tsc -p jsconfig.json",
"lint:watch": "tsc -p jsconfig.json --watch --preserveWatchOutput"
}
} bun check
The Bun documentation (Bun 1.4) describes a built-in checker, bun check, that reads tsconfig.json, writes no files, and aims to report the same errors as tsc from TypeScript 7. It reports errors in JavaScript files when checkJs is on. That documentation talks about tsconfig.json and does not mention jsconfig.json, so with bun check name the file tsconfig.json. We have not run it; the example on this page is checked with tsc 5.9.
Per the same documentation, bun --check file.js checks before it runs, and bun test --check checks before testing.
What it catches
Bun's APIs are typed like any other: a misspelled method on Bun.file() is an error.
const port = Number(Bun.env.PORT ?? 3000);
const server = Bun.serve({
port,
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/notes") {
return new Response(await Bun.file("notes.txt").txt());error TS2551: Property 'txt' does not exist on type 'BunFile'. Did you mean 'text'?
}
return Response.json({ path: url.pathname });
},
});
console.log(`Listening on ${server.url}`);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "preserve",
"moduleResolution": "bundler",
"target": "esnext",
"lib": [
"esnext"
],
"moduleDetection": "force",
"types": [
"bun"
],
"skipLibCheck": true
},
"include": [
"src/**/*.js"
]
} The example project
A small Bun.serve server that reads a port from Bun.env and a file with Bun.file.
const port = Number(Bun.env.PORT ?? 3000);
const server = Bun.serve({
port,
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === "/notes") {
return new Response(await Bun.file("notes.txt").text());
}
return Response.json({ path: url.pathname });
},
});
console.log(`Listening on ${server.url}`);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"module": "preserve",
"moduleResolution": "bundler",
"target": "esnext",
"lib": [
"esnext"
],
"moduleDetection": "force",
"types": [
"bun"
],
"skipLibCheck": true
},
"include": [
"src/**/*.js"
]
} In your editor
VS Code reads this jsconfig.json with no further setup. To make it use the same TypeScript as npm run lint, see VS Code.
Sources
- TypeScript · Bun docs
- Type checking · Bun docs
- HTTP server · Bun docs
- @types/bun · npm
Last reviewed 20 October 2026.