| |

TypeScript 92 ๐Ÿ”ท TypeScript with Deno and Bun

The previous chapter covered Node.js and Express โ€” the traditional backend stack, where TypeScript is a layer added on top of a runtime that was designed for JavaScript. Deno and Bun approach TypeScript differently. Both runtimes were built from the ground up with TypeScript as a first-class language, not an afterthought. Neither requires tsc to execute code. Both strip types at runtime and execute the result. The difference is in what they do with the types after stripping โ€” and what they expect you to do for type checking.

Deno’s philosophy is security and standards compliance. It treats TypeScript as a first-class language, compiles it internally with its own embedded TypeScript compiler, and type-checks in strict mode by default . Bun’s philosophy is speed and compatibility. It strips types using its own transpiler, runs TypeScript natively, and positions itself as a drop-in replacement for Node.js with a focus on performance .

Key point: Neither Deno nor Bun type-checks your code at runtime. Type stripping is a transformation, not a validation. Deno provides deno check and Bun expects you to run tsc --noEmit or bunx tsc --noEmit separately . The type annotations you write are erased before execution. The runtime does not know what types you intended, and it will not tell you if your code violates them.


Why Deno and Bun matter for TypeScript

Node.js was designed for JavaScript, and TypeScript support was retrofitted through external tools. Deno and Bun were designed after TypeScript became the dominant language for serious JavaScript development. That timing shapes their architecture.

The build-step elimination. In a Node.js TypeScript project, you either compile with tsc before running, or you use a tool like ts-node or tsx. Both add a step between writing the code and running it. Deno and Bun eliminate that step. deno run main.ts and bun run main.ts both execute the TypeScript file directly. The runtime strips the types and runs the result .

The security model. Deno was designed with security as a first principle. JavaScript in Node.js has unrestricted access to the filesystem, network, and environment. Deno requires explicit permission for each of these. This affects how you write backend code, and it affects how TypeScript is configured. Deno’s type definitions include the permission model, so the compiler knows which APIs require flags .

The performance model. Bun is built on JavaScriptCore, the engine that powers Safari, and uses Zig for its runtime implementation. Its TypeScript transpiler is written in Zig and is significantly faster than tsc or swc. For projects where startup time and execution speed matter โ€” serverless functions, CLI tools, test suites โ€” Bun’s performance advantage is measurable .

The trade-off. Deno and Bun both sacrifice some Node.js compatibility for their respective advantages. Deno’s permission model means existing Node.js code that reads files without flags will fail. Bun’s focus on speed means some edge cases in Node.js’s module resolution may behave differently. Both have npm: and node: compatibility layers, but neither is a perfect drop-in for every project.


a. TypeScript in Deno

Deno treats TypeScript as a first-class language, the same as JavaScript or WebAssembly. You can run or import TypeScript without installing anything beyond the Deno CLI. Deno includes its own TypeScript compiler, built into the runtime, which transpiles TypeScript to JavaScript and stores the result in a cache .

The type-checking behavior is the first thing to understand. Deno type-checks in strict mode by default, and it also enables noImplicitOverride, which tsc leaves off even under strict . But type checking is not performed before execution by default. deno run main.ts transpiles the file and runs it without checking types. To check types before running, you use deno run --check main.ts or deno check main.ts .

// main.ts
function greet(name: string): string {
  return `Hello, ${name}`;
}

console.log(greet("Deno"));

Running deno run main.ts executes the code. Running deno check main.ts checks the types. Running deno run --check main.ts does both, and exits before execution if a type error is found.

Deno’s configuration lives in deno.json rather than tsconfig.json for Deno-first projects. The compilerOptions section accepts a subset of TypeScript’s options. Deno’s defaults are strict and modern, so most projects need no configuration at all . The options that Deno ignores are those that shape emitted JavaScript โ€” target, module, outDir, sourceMap โ€” because Deno does not write JavaScript files to disk. It keeps the transpiled output in its internal cache .

The lib setting is where Deno diverges from standard TypeScript. Deno’s default lib is ["deno.window"], which includes the Deno global namespace and the web platform APIs that Deno implements . If you want code that also runs in the browser, you add "dom" and "dom.iterable" to the lib array, and use "deno.ns" instead of "deno.window" to avoid conflicts between the two libraries’ global declarations .

// deno.json
{
  "compilerOptions": {
    "lib": ["dom", "dom.iterable", "dom.asynciterable", "deno.ns"]
  }
}

This configuration allows a single file to be type-checked against both the browser and Deno environments. The deno.ns library provides the Deno global without the full deno.window library, avoiding conflicts with dom.

Deno’s module resolution is also different from tsc. Deno uses explicit specifiers โ€” import { foo } from "./foo.ts" โ€” rather than tsc‘s ambiguous module resolution. When consuming JavaScript that has an associated .d.ts file, Deno does not automatically pick up the .d.ts the way tsc does. You must explicitly specify where the types are located .


b. TypeScript in Bun

Bun executes TypeScript natively without a separate compilation step. Its runtime includes a built-in TypeScript transpiler written in Zig. When you run a .ts or .tsx file, Bun strips the types on the fly and executes the resulting JavaScript in the same process, with no intermediate files written to disk .

Bun’s type stripping is similar to Node.js’s, but with broader support. Bun handles all TypeScript syntax, including enum, namespaces with runtime values, and parameter properties, without requiring experimental flags . The ts loader “strips out all TypeScript syntax, then behaves identically to the js loader” . Bun does not perform type checking.

// index.ts
const server = Bun.serve({
  port: 3000,
  fetch(request) {
    return new Response("Hello from Bun");
  },
});

console.log(`Listening on ${server.url}`);

Running bun run index.ts starts the server immediately. No build step, no tsc, no configuration.

The TypeScript configuration for Bun is also different from a Node.js project. Bun recommends a specific tsconfig.json that enables features TypeScript does not allow by default: top-level await, importing .ts files by extension, and JSX . The key settings are:

{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "Preserve",
    "moduleDetection": "force",
    "jsx": "react-jsx",
    "allowJs": true,
    "types": ["bun"],
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true
  }
}

The "types": ["bun"] entry is required for TypeScript 6.0 and later, which no longer auto-discovers @types/* packages . The "moduleResolution": "bundler" setting matches Bun’s resolution algorithm, which allows importing .ts files directly. The "noEmit": true setting tells TypeScript that Bun handles execution, so TypeScript should only be used for type checking .

Bun reads paths from tsconfig.json and uses them for runtime module resolution. Path aliases configured for TypeScript work at runtime without a separate bundler configuration . Bun also supports importing JSON, TOML, YAML, and other file types directly, with types provided by @types/bun .

Type checking in Bun is entirely separate from execution. bunx tsc --noEmit runs the TypeScript compiler in check-only mode. If TypeScript is installed as a dev dependency, bun run tsc --noEmit works. The recommended package.json script is "typecheck": "tsc --noEmit" .


c. Choosing Between Deno and Bun

Both runtimes eliminate the build step for TypeScript, but they target different use cases.

Deno for security-sensitive and standards-compliant projects. Deno’s permission model means that code cannot access the filesystem, network, or environment without explicit flags. This is valuable for running untrusted code, for CLI tools that should be transparent about what they access, and for projects where the principle of least privilege matters. Deno’s strict-by-default type checking and its alignment with web standards make it a good choice for code that also runs in the browser .

Bun for performance-sensitive and Node.js-compatible projects. Bun’s JavaScriptCore engine and Zig-based runtime give it a measurable speed advantage over Node.js for many workloads. Its compatibility with Node.js’s module resolution, require(), and npm packages means existing Node.js projects can often run under Bun with minimal changes. The built-in bundler, test runner, and package manager make Bun a complete toolkit rather than just a runtime .

The shared limitation. Neither runtime type-checks at execution time. Deno provides deno check and deno run --check. Bun expects tsc --noEmit. In both cases, the type checking is a separate step that must be run in CI or in an editor that understands TypeScript. The runtime will happily execute code with type errors, just as Node.js executes JavaScript with logical errors.

The migration cost. Moving an existing Node.js project to Deno requires adapting to the permission model and the explicit module resolution. Moving to Bun is generally easier because Bun implements the Node.js module resolution algorithm and supports both require() and import . For new projects, the choice depends on whether security (Deno) or speed and compatibility (Bun) is the priority.


Complete Example Session

This session builds a small HTTP server and a CLI tool in both Deno and Bun, demonstrating the runtime-specific type definitions and the type-checking workflow.

// ============================================
// PART 1: THE DENO HTTP SERVER
// ============================================

// deno-server.ts
Deno.serve({ port: 8000 }, (request: Request): Response => {
  const url = new URL(request.url);
  return new Response(`Path: ${url.pathname}`, {
    headers: { "content-type": "text/plain" },
  });
});

// Run: deno run --allow-net deno-server.ts
// Check: deno check deno-server.ts

// ============================================
// PART 2: THE DENO CLI TOOL
// ============================================

// deno-cli.ts
const args = Deno.args;
if (args.length === 0) {
  console.error("Usage: deno run --allow-read deno-cli.ts <file>");
  Deno.exit(1);
}

const filename = args[0];
try {
  const content = await Deno.readTextFile(filename);
  const lines = content.split("\n").length;
  console.log(`${filename}: ${lines} lines`);
} catch (error) {
  if (error instanceof Deno.errors.NotFound) {
    console.error(`File not found: ${filename}`);
    Deno.exit(2);
  }
  throw error;
}

// Run: deno run --allow-read deno-cli.ts package.json
// The Deno.errors.NotFound type is available from deno.ns.

// ============================================
// PART 3: THE BUN HTTP SERVER
// ============================================

// bun-server.ts
const server = Bun.serve({
  port: 3000,
  fetch(request: Request): Response {
    const url = new URL(request.url);
    return new Response(`Path: ${url.pathname}`, {
      headers: { "content-type": "text/plain" },
    });
  },
});

console.log(`Server running at ${server.url}`);

// Run: bun run bun-server.ts
// The Bun.serve types are provided by @types/bun.

// ============================================
// PART 4: THE BUN CLI TOOL
// ============================================

// bun-cli.ts
const args = Bun.argv.slice(2);
if (args.length === 0) {
  console.error("Usage: bun run bun-cli.ts <file>");
  process.exit(1);
}

const filename = args[0];
const file = Bun.file(filename);

if (!(await file.exists())) {
  console.error(`File not found: ${filename}`);
  process.exit(2);
}

const content = await file.text();
const lines = content.split("\n").length;
console.log(`${filename}: ${lines} lines`);

// Run: bun run bun-cli.ts package.json
// Bun.file returns a BunFile with exists() and text() methods.

// ============================================
// PART 5: THE DENO CONFIGURATION
// ============================================

// deno.json
{
  "compilerOptions": {
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true
  },
  "tasks": {
    "check": "deno check **/*.ts",
    "run:server": "deno run --allow-net deno-server.ts"
  }
}

// Run: deno task check
// Run: deno task run:server

// ============================================
// PART 6: THE BUN CONFIGURATION
// ============================================

// tsconfig.json
{
  "compilerOptions": {
    "lib": ["ESNext"],
    "target": "ESNext",
    "module": "Preserve",
    "moduleDetection": "force",
    "allowJs": true,
    "types": ["bun"],
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true
  }
}

// package.json
{
  "scripts": {
    "typecheck": "tsc --noEmit",
    "start": "bun run bun-server.ts"
  }
}

// Run: bun run typecheck
// Run: bun run start

// ============================================
// PART 7: THE DENO TYPE CHECKING
// ============================================

// Check without running
deno check deno-server.ts

// Check and run
deno run --check --allow-net deno-server.ts

// Check all TypeScript files
deno check **/*.ts

// Type checking is NOT run by default with deno run.
// The --check flag enables it.

// ============================================
// PART 8: THE BUN TYPE CHECKING
// ============================================

// Bun does not type-check at all.
// Use tsc directly:
bunx tsc --noEmit

// Or if TypeScript is a dev dependency:
bun run tsc --noEmit

// Add to package.json scripts for CI:
// "typecheck": "tsc --noEmit"

// ============================================
// PART 9: THE DENO TEST RUNNER
// ============================================

// deno-test.ts
import { assertEquals } from "jsr:@std/assert";

function add(a: number, b: number): number {
  return a + b;
}

Deno.test("add returns sum", () => {
  assertEquals(add(2, 3), 5);
});

// Run: deno test
// Type checking is enabled by default during tests.
// Skip with: deno test --no-check

// ============================================
// PART 10: THE BUN TEST RUNNER
// ============================================

// bun-test.test.ts
import { expect, test } from "bun:test";

function add(a: number, b: number): number {
  return a + b;
}

test("add returns sum", () => {
  expect(add(2, 3)).toBe(5);
});

// Run: bun test
// Bun's test runner does not type-check.
// Use tsc --noEmit separately.

The ten parts cover the Deno HTTP server, the Deno CLI tool, the Bun HTTP server, the Bun CLI tool, the Deno configuration, the Bun configuration, Deno type checking, Bun type checking, the Deno test runner, and the Bun test runner.


Quick Reference

The Runtime Comparison

FeatureDenoBun
TypeScript executionNativeNative
Type checkingdeno checktsc --noEmit
Check before rundeno run --checkNot built-in
Strict mode defaultโœ… YesDepends on tsconfig.json
Config filedeno.jsontsconfig.json
Type definitionsBuilt-in (deno.ns)@types/bun
Module resolutionExplicit specifiersNode.js algorithm
Permission modelโœ… YesโŒ No
enum supportโœ… Yesโœ… Yes

The Deno Type-Checking Commands

CommandPurpose
deno check main.tsType-check without running
deno check --all main.tsCheck remote modules and npm
deno run --check main.tsCheck before running
deno testType-checking enabled by default
deno test --no-checkSkip type checking in tests

The Bun Configuration Settings

SettingValuePurpose
lib["ESNext"]Latest JavaScript features
target"ESNext"Output target
module"Preserve"Bun handles import/export
moduleResolution"bundler"Matches Bun’s resolution
allowImportingTsExtensionstrueImport .ts files directly
noEmittrueTypeScript only checks
types["bun"]Load Bun global types

The Deno lib Settings

LibraryPurpose
"deno.window"Default Deno runtime library
"deno.ns"Deno global namespace only
"deno.worker"Web worker Deno library
"dom"Browser DOM (conflicts with deno.window)
"dom.iterable"DOM iterables

Best Practices

โœ… Do This:

// Use deno check in CI
deno check **/*.ts                                              // โœ…
// Use deno run --check for type-checked execution
deno run --check main.ts                                        // โœ…
// Add "types": ["bun"] for TypeScript 6.0+
"types": ["bun"]                                                // โœ…
// Run tsc --noEmit for Bun type checking
bunx tsc --noEmit                                               // โœ…
// Use the recommended Bun tsconfig
"moduleResolution": "bundler"                                   // โœ…

โŒ Don’t Do This:

// Don't assume Deno type-checks on run
deno run main.ts  // does NOT type-check                           // โŒ
// Don't assume Bun type-checks at all
bun run main.ts  // no type checking                               // โŒ
// Don't forget @types/bun
// Without it, Bun global is untyped.                             // โŒ
// Don't use dom with deno.window
"lib": ["deno.window", "dom"]  // conflicts                         // โŒ
// Don't rely on Deno permissions in Bun
// Bun has no permission model.                                  // โŒ

Common Pitfalls

PitfallWhy It HappensFix
Deno runs code with type errorsType checking not enabled by defaultUse deno run --check
Bun runs code with type errorsBun never type-checksRun tsc --noEmit separately
Cannot find name 'Bun'Missing @types/bun or types configInstall @types/bun, add "types": ["bun"]
Cannot find name 'Deno'Missing deno.ns in libAdd "deno.ns" to lib
dom conflicts with deno.windowBoth declare global typesUse "deno.ns" instead of "deno.window"
.d.ts file not foundDeno does not auto-discoverExplicitly specify the path
Import .ts fails in BunMissing allowImportingTsExtensionsAdd to tsconfig.json

Real-World Examples

1. Deno HTTP Server

Deno.serve({ port: 8000 }, (req) => new Response("Hello"));

2. Deno CLI Tool

const args = Deno.args;
if (args.length === 0) Deno.exit(1);

3. Deno File Read

const content = await Deno.readTextFile("file.txt");

4. Deno Check

deno check main.ts

5. Deno Run with Check

deno run --check main.ts

6. Bun HTTP Server

const server = Bun.serve({ port: 3000, fetch(req) { return new Response("Hello"); } });

7. Bun CLI Tool

const args = Bun.argv.slice(2);

8. Bun File Read

const file = Bun.file("file.txt");
const content = await file.text();

9. Bun Type Check

bunx tsc --noEmit

10. Deno Test

Deno.test("name", () => { assertEquals(1, 1); });

Visual

The TypeScript Execution Pipeline

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  DENO EXECUTION                              โ”‚
โ”‚                                              โ”‚
โ”‚  main.ts โ”€โ”€> [type strip] โ”€โ”€> cache โ”€โ”€> run  โ”‚
โ”‚                                              โ”‚
โ”‚  Type checking is separate:                  โ”‚
โ”‚  deno check main.ts                          โ”‚
โ”‚                                              โ”‚
โ”‚  Or combined:                                โ”‚
โ”‚  deno run --check main.ts                    โ”‚
โ”‚                                              โ”‚
โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค
โ”‚  BUN EXECUTION                               โ”‚
โ”‚                                              โ”‚
โ”‚  main.ts โ”€โ”€> [type strip] โ”€โ”€> run            โ”‚
โ”‚                                              โ”‚
โ”‚  No cache, no type checking.                 โ”‚
โ”‚  Type checking is entirely external:         โ”‚
โ”‚  bunx tsc --noEmit                           โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Deno lib Configuration

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  DENO lib SETTINGS                           โ”‚
โ”‚                                              โ”‚
โ”‚  Default:                                    โ”‚
โ”‚  lib: ["deno.window"]                        โ”‚
โ”‚    โ””โ”€ Deno global + web APIs                 โ”‚
โ”‚                                              โ”‚
โ”‚  Deno + Browser:                             โ”‚
โ”‚  lib: ["dom", "dom.iterable", "deno.ns"]     โ”‚
โ”‚    โ””โ”€ Browser globals + Deno global          โ”‚
โ”‚    โ””โ”€ deno.ns avoids conflict with dom       โ”‚
โ”‚                                              โ”‚
โ”‚  โŒ Don't use deno.window + dom together     โ”‚
โ”‚     (conflicting global declarations)        โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

The Bun tsconfig Requirements

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  BUN tsconfig.json                           โ”‚
โ”‚                                              โ”‚
โ”‚  "lib": ["ESNext"]                           โ”‚
โ”‚  "target": "ESNext"                          โ”‚
โ”‚  "module": "Preserve"                        โ”‚
โ”‚  "moduleResolution": "bundler"               โ”‚
โ”‚  "allowImportingTsExtensions": true          โ”‚
โ”‚  "verbatimModuleSyntax": true                โ”‚
โ”‚  "noEmit": true                              โ”‚
โ”‚  "types": ["bun"]                            โ”‚
โ”‚                                              โ”‚
โ”‚  These settings match Bun's runtime.         โ”‚
โ”‚  "noEmit" tells TypeScript to only check.    โ”‚
โ”‚  "types" loads @types/bun for globals.       โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Type Checking Workflow

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  TYPE CHECKING WORKFLOW                      โ”‚
โ”‚                                              โ”‚
โ”‚  Deno:                                       โ”‚
โ”‚    deno check **/*.ts    โ†’ CI                โ”‚
โ”‚    deno run --check main โ†’ development       โ”‚
โ”‚    deno test             โ†’ tests (auto)      โ”‚
โ”‚                                              โ”‚
โ”‚  Bun:                                        โ”‚
โ”‚    bunx tsc --noEmit     โ†’ CI                โ”‚
โ”‚    bun run tsc --noEmit  โ†’ development       โ”‚
โ”‚                                              โ”‚
โ”‚  Neither runtime checks types at run time.   โ”‚
โ”‚  Both require an explicit check command.     โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

ItemValue
Deno TypeScriptNative, first-class, built-in compiler
Deno type checkingdeno check, deno run --check
Deno configdeno.json with compilerOptions
Deno strict defaultโœ… Yes
Deno lib default["deno.window"]
Bun TypeScriptNative, type-stripping transpiler
Bun type checkingtsc --noEmit (external)
Bun configtsconfig.json with "types": ["bun"]
Bun types package@types/bun
Bun module resolutionNode.js algorithm

Key takeaways:

  • Both Deno and Bun execute TypeScript natively without a build step. They strip type annotations at runtime and run the resulting JavaScript. Neither writes intermediate .js files to disk .
  • Neither runtime type-checks at execution time. Deno provides deno check and deno run --check for explicit checking. Bun expects tsc --noEmit as a separate step. Type checking is never automatic .
  • Deno’s type checking is strict by default. It enables strict and noImplicitOverride, which tsc leaves off even under strict mode. Deno’s configuration lives in deno.json .
  • Deno’s lib settings differ from standard TypeScript. The default is ["deno.window"], which includes the Deno global namespace and web APIs. For browser-compatible code, use ["dom", "dom.iterable", "deno.ns"] instead .
  • Bun requires "types": ["bun"] in tsconfig.json for TypeScript 6.0+. Starting with TypeScript 6.0, the types field defaults to an empty array, so @types/bun must be explicitly listed. The recommended tsconfig.json also sets "moduleResolution": "bundler", "allowImportingTsExtensions": true, and "noEmit": true .
  • Deno has a permission model; Bun does not. Deno requires explicit flags for filesystem, network, and environment access. Bun follows Node.js’s unrestricted model. This affects both runtime behavior and the type definitions for permission-gated APIs .
  • Bun implements the Node.js module resolution algorithm. It supports both require() and import, and reads paths from tsconfig.json for runtime resolution. This makes migration from Node.js easier than migration to Deno .

Remember: Deno and Bun both treat TypeScript as a first-class language, but neither treats it as a type-checked language. The type annotations are erased before execution. Deno gives you deno check and strict-by-default configuration. Bun gives you speed, Node.js compatibility, and a recommended tsconfig.json that expects external type checking. The discipline is the same in both cases: write TypeScript, run it directly, and check the types as a separate step in CI. The runtime will not tell you if the types are wrong. Only the compiler will.


Stop using slow, ad-bloated tool sites! ๐Ÿคฎ

๐Ÿ”Ž Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
โœ… Finance (Mortgage, Interest, Inflation)
โœ… Tech (Base64, JSON, Dev Suite, IP)
โœ… Health (BMI, BMR, TDEE)
โœ… Productivity (Timer, Workspace, QR)

โšก๏ธ Fast & Private
๐Ÿ”’ No data leaves your device
๐Ÿ’Ž 100% Free

๐Ÿ”— Use it now: https://tools.kandz.me
๐Ÿ”– Bookmark itโ€”youโ€™ll need it later!