opencode is a terminal coding agent you start with opencode in the project folder. It reads your project files and any AGENTS.md instructions, then edits code and runs commands. For TypeScript, tsc --noEmit is the fastest reliable check, and strict mode turns type errors into concrete guidance. If you are new to the agent, see How to use opencode: a step-by-step guide.
Type checking gives opencode a fast feedback loop
Concretely, TypeScript gives opencode a feedback loop that plain JavaScript does not. After each change the agent can run the compiler and read exact positions of type mismatches. This works especially well in strict mode, where noImplicitAny, strictNullChecks, and noUncheckedIndexedAccess make most invalid code fail at compile time. The agent can refactor a discriminated union, update a generic constraint, or replace any with inferred types, then verify with tsc. The limit is that opencode may still write plausible-looking code that only fails under complex type relationships, so you still need to review diffs and run the test suite.
Make AGENTS.md your project contract
The most important file you can add is AGENTS.md in the repo root. Keep it short and command-focused. It should not explain what TypeScript is; it should tell the agent the exact commands, folder conventions, and rules that are easy to break. For general agent usage, see opencode; this guide focuses on TypeScript specifics.
A realistic AGENTS.md example:
# AGENTS.md
## Commands
- Install: pnpm install
- Build: pnpm build (`tsc -b`)
- Test: pnpm test (`vitest run`)
- Lint: pnpm lint (`eslint .`)
- Typecheck: pnpm typecheck (`tsc --noEmit`)
- Typecheck one package: pnpm --filter @acme/api exec tsc --noEmit
## Folders
- packages/api/src: API route handlers and zod schemas
- packages/shared/src: domain types, utility types, no server-only imports
- packages/web/src: React components, only import from packages/shared
## TypeScript rules
- tsconfig.base.json enables strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes.
- Do not add `any`, `@ts-ignore`, or `@ts-expect-error` without an explicit reason in a comment.
- Prefer type predicates and `satisfies` over `as` casts.
- Keep generic constraints minimal; do not over-constrain `T` unless every caller needs it.
- After any edit, run `pnpm typecheck` and fix all errors before saying the task is done.
How to run a TypeScript change loop
Treat each task as a cycle: plan the change in the prompt, let the agent edit one small scope, run typecheck and tests, then review the diff before moving on. Avoid asking for a large refactor and a new feature at the same time. If the agent runs into type errors, ask it to explain what it changed and paste the tsc output; don’t just accept a fix that adds a cast.
Example prompts for TypeScript tasks:
- “Refactor this function to remove the
anyreturn type. Keep all existing call sites type-correct and run typecheck.” - “Add a
statusfield to theOrderinterface and update the discriminated union inprocessOrderso each branch narrows correctly.” - “Rewrite the generic
fetchListfunction so it accepts readonly arrays and returnsReadonlyArray<T>without breaking existing callers.” - “Find all uses of
asinpackages/api/srcand replace them with type predicates orsatisfieswhere possible.” - “Move the
Usertype frompackages/webtopackages/sharedand update imports; run build and tests.”
What opencode gets right and where to watch closely
opencode handles mechanical, type-driven work well: extracting interfaces from object literals, updating function signatures across many files, changing generic bounds, converting enums to union types, and removing any when inference is obvious. It also does well with straightforward refactors like flipping optional properties or fixing import paths after moving types.
Watch closely for these TypeScript-specific pitfalls:
- Casts: the agent may add
as unknown as Xto silence errors. This hides real issues and breaks later. Require type predicates orsatisfies. - Generic over-constraining: the agent may add
extends SomeObjectto avoid an error but then rejects valid inputs. Check that constraints are truly needed. - Narrowing in callbacks: narrowing does not persist inside callbacks. The agent may write code that reads an optional property after a check in a
setTimeoutand fails understrictNullChecks. - Strict optional and indexed access:
exactOptionalPropertyTypesandnoUncheckedIndexedAccesstrip up the agent. It may assume optional property is always defined or indexed access returnsTnotT | undefined. - Monorepo project references: the agent may run
tscat root and miss package-specific config, or import from a package not listed in references. Ask it to use the per-package typecheck command. satisfiesvsas: the agent may usesatisfiesincorrectly when the value needs widening; verify that the inferred type is the one you want.
Verify with tsc, tests, and CI
Make typecheck the first gate. The most useful command is pnpm typecheck or pnpm exec tsc --noEmit. After every agent turn, run it yourself before reviewing the diff. If the agent says tests pass, confirm by running the test script, because the agent may run a subset or not run tests at all. In CI, keep tsc --noEmit as a separate job from tests so type errors don’t hide behind a failing test suite. For monorepos, typecheck each touched package with --filter or project references.
| Command | What it verifies | When to run |
|---|---|---|
pnpm typecheck | Type errors under the project tsconfig | After every agent edit, before commit |
pnpm test | Unit/component behavior | After typecheck passes; for behavior changes |
pnpm lint | ESLint rules, including banned any or strict casts | Before review; catches style and unsafe patterns |
pnpm build | Project references, emit, and monorepo boundaries | Before merge; catches cross-package import errors |
Parallel agents with AgentVera for TypeScript
For TypeScript work across multiple agent sessions, AgentVera helps by running opencode and other CLI agents in parallel, each in its own git worktree, so agents don’t overwrite each other’s files while changing shared types. Its automatic code review from a second model catches type-level mistakes, and links findings to file:line, which is useful when a change spans several packages. Checkpoints let you undo a bad type refactor and replay the session. That combination matters because TypeScript changes often ripple through imports and generics.
Keep the type gate tight
opencode is most useful on TypeScript when you give it precise compiler rules and a short loop. Keep AGENTS.md concrete, run tsc --noEmit after every change, review diffs around generics and narrowing, and use CI as the final type gate. That discipline turns a helpful coding agent into a reliable part of a typed codebase.