TypeScript setup
esrun does not execute TypeScript, nor does it inject ambient globals like Bun or process. esdev runs TypeScript directly — types erased, never checked — and the definitions below are what your editor and tsc --noEmit use.
One-command setup
esdev --install-types
It adds @opentf/esrun-types as a dev dependency and adds it to compilerOptions.types — creating a tsconfig.json if you don't have one, or merging into an existing one without touching your other settings.
Which package manager it uses is decided in the order those answers are worth anything:
"packageManager" in package.json | The project saying which one it uses — the field corepack reads. It is there before a lockfile is: a fresh clone, a scaffold, a CI job at its first step |
| The lockfile | bun.lock, bun.lockb, pnpm-lock.yaml, yarn.lock, package-lock.json — evidence of what actually installed |
| What is installed here | With the project silent, the question is which manager can run at all |
npm is the last word rather than the first: "npm is always there" is exactly the assumption that produces npm: command not found in a container that ships only bun. A declared manager that is not installed is still the answer — it prints the line to run rather than reaching for a different one, because installing with the wrong manager leaves the wrong lockfile behind.
What it configures
{ "compilerOptions": { "target": "ESNext", "module": "ESNext", "moduleResolution": "bundler", "strict": true, "types": ["@opentf/esrun-types"] }, "include": ["**/*.ts"] }
types is what editors and language servers load globally, so the runtime:* modules resolve everywhere, not just per-file.
With no lib, TypeScript uses the default for your target — lib.esnext.full for ESNext — which already includes the web APIs this runtime provides: fetch, URL, crypto, the streams, TextEncoder, and Temporal from TypeScript 7. Setting lib explicitly replaces that default, so a config naming only ["ESNext"] loses all of them.
npm install --save-dev @opentf/esrun-types
Then add "types": ["@opentf/esrun-types"] to compilerOptions, or put /// <reference types="@opentf/esrun-types" /> in one file.
Use it
Your editor now provides intellisense, inline docs, and type checking for every built-in module:
import { file } from "runtime:fs"; // Your IDE knows `text()` returns a Promise<string> const data = await file("./config.json").text();