Skip to main content
meow runs TypeScript natively. There is no separate compile step and no tsconfig.json to write before you can execute a .ts file. Point meow at the source and go:
meow run main.ts

How it works: in-place type-stripping

meow does not transpile or downlevel your code. It parses the file once with Oxc, then blanks the type-only spans to whitespace directly over the source string — preserving every byte position of the runtime code that remains. Because positions are preserved, meow emits no source maps: a stack trace points at the original line and column already. And because nothing is rewritten, modern JavaScript passes straight through to V8 untouched.
// what you write
function add(a: number, b: number): number {
  return a + b;
}

// what V8 runs (types blanked, positions intact — not shown rewritten)
function add(a        , b        )         {
  return a + b;
}
meow targets modern JavaScript (esnext). It does not downlevel to older syntax — there is no target: es5. If your runtime is V8, you already have the modern features.

Erasable syntax only

Type-stripping can only remove syntax, never generate runtime code. So meow supports the erasable subset of TypeScript — the same boundary Node’s native type-stripping and Deno draw. These all work:
  • Type annotations, interface, type aliases
  • Generics, as/satisfies, non-null !
  • import type / export type
Constructs that would require emitting runtime code are not supported, because there’s nothing to strip them down to:
Not supportedWhyUse instead
enumemits a runtime objecta const object + union type
namespace with valuesemits runtime codeES modules
constructor parameter propertiesemits assignmentsexplicit field declarations
experimental/emit decoratorsrewrite the classplain functions/wrappers
Keep imports and exports explicit. The generated type config uses verbatimModuleSyntax, so use import type { Foo } for type-only imports — it makes type-stripping unambiguous and your intent clear.

Importing TypeScript files

meow’s resolver is built for real-world TS projects, including one helpful behavior worth calling out:

.js specifiers fall back to .ts source

Modern TypeScript projects often write import "./foo.js" even though only foo.ts (or .tsx/.mts) exists on disk — TypeScript’s own convention. meow’s resolver transparently falls back from the explicit .js extension to the TypeScript source sibling before declaring a module missing. You can also import .ts extensions directly (import "./foo.ts"), which allowImportingTsExtensions in the generated config permits.
import { add } from "./math.js";   // resolves math.ts if math.js doesn't exist
import { sub } from "./math.ts";   // explicit .ts also works

JSX / TSX

.jsx and .tsx are parsed and transformed by the same Oxc pipeline — no extra configuration.

Type-checking is separate from running

meow runs TypeScript by stripping types; it does not type-check during execution (just like Node’s type-stripping). That’s a feature: startup stays fast, and type errors don’t block a quick run. When you want full type-checking, run the dedicated verb — it delegates to tsc over the generated shadow config and renders the results as meow diagnostics:
meow check
See Type checking for details, and Editor setup for how meow keeps your IDE’s types in sync via meow sync.

Type checking

Run tsc over a generated config, with beautiful diagnostics.

Web APIs

The web-standard globals available to your TypeScript.