Skip to content

TypeScript and modules

What Elide's TypeScript type stripping accepts and rejects, JSX, type checking with tsc and @elide-dev/types, and how ES modules, CommonJS, JSON and exports resolve.

On this page

Elide runs .ts, .mts, .cts and .tsx files by removing their types; it does not type-check them or read tsconfig.json.

TypeScript syntax

SyntaxStatus
Type annotations, interfaces, type, generics, as, satisfies, !Removed
import type, import { type X }Removed
enum, const enumCompiled to objects
namespaceCompiled
Constructor parameter properties (constructor(public x: number))Compiled
abstract, declare fields, override, accessorSupported
import fs = require("node:fs")Supported
Decorators on classes and methodsStandard decorators: each receives (value, context)
experimentalDecorators-style decoratorsNot supported; they receive standard arguments
Parameter decorators (constructor(@inject x))SyntaxError: … expected BindingIdentifier or BindingPattern
<string>value type assertionsPrecompiler failed with 1 diagnostic(s): … [ERROR] Unexpected token; use value as string
export = valueSyntaxError: … Expected an operand but found export
tsconfig.json pathsIgnored: TypeError: Module not found: '@lib/math'

Imports may name the .ts file, a .js extension, or no extension; all three resolve to math.ts:

import { add } from "./src/lib/math.ts";
import { add as add2 } from "./src/lib/math.js";
import { add as add3 } from "./src/lib/math";
console.log(add(1, 2), add2(2, 2), add3(3, 3));
3 4 6

JSX

.tsx files use the automatic JSX runtime and import react/jsx-runtime. Install React yourself:

// app.tsx
import { renderToString } from "react-dom/server";

function Hello({ name }: { name: string }) {
  return <p>hello {name}</p>;
}

console.log(renderToString(<Hello name="elide" />));
elide install --ecosystems=npm   # react, react-dom in package.json
elide app.tsx
<p>hello <!-- -->elide</p>
InputResult
/** @jsxImportSource preact */ at the top of a .tsx fileImports preact/jsx-runtime
jsxImportSource in tsconfig.jsonIgnored; React is used
/** @jsx h */Ignored; React elements are created
JSX in a .jsx fileSyntaxError: … Expected an operand but found <; rename it to .tsx

Check types

Install TypeScript and run its compiler through Elide:

{
  "scripts": { "typecheck": "tsc --noEmit" },
  "devDependencies": { "typescript": "^5.9.0", "@types/node": "^24.0.0" }
}
{
  "compilerOptions": {
    "module": "nodenext",
    "target": "esnext",
    "strict": true,
    "noEmit": true,
    "allowImportingTsExtensions": true,
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "types": ["node"]
  }
}
elide install --ecosystems=npm
elide run typecheck              # or: elide run tsc
bad-types.ts(1,7): error TS2322: Type 'string' is not assignable to type 'number'.

tsc exits 2 on type errors. Pass compiler options after --: elide run tsc -- --version. erasableSyntaxOnly makes tsc reject enums, namespaces and parameter properties; drop it if you use them.

Elide types

@elide-dev/types declares Elide’s own globals and modules and pulls in @types/node. Add it as a dev dependency and name it in types:

{
  "type": "module",
  "scripts": { "typecheck": "tsc --noEmit" },
  "devDependencies": { "typescript": "^5.9.0", "@elide-dev/types": "nightly" }
}
{
  "compilerOptions": {
    "module": "nodenext",
    "target": "esnext",
    "strict": true,
    "noEmit": true,
    "allowImportingTsExtensions": true,
    "types": ["@elide-dev/types"]
  }
}
// main.ts
import { Database } from "elide:postgres";
import { readFileSync } from "node:fs";

const bytes: number = readFileSync("package.json").length;
console.log(`Elide ${Elide.version}: ${bytes} bytes`);
export const open = (url: string) => Database.connect(url);
elide install --ecosystems=npm
elide run typecheck
elide main.ts
Elide 1.6.0: 149 bytes
APIDeclared
Elide.version, debug, release, buildModeYes
Elide.targetArchitectureTyped as boolean; the value is a string
Elide.serve()No: Property 'serve' does not exist
elide:postgres, elide:mysqlYes
elide:sqlite, elide:cel, elide:telemetryNo
import … from "./script.py"Yes, as any
node:* modulesYes, through @types/node

The nightly tag tracks the newest declarations; latest is older.

ES modules and CommonJS

FileModule system
.mjs, .mtsES module
.cjs, .ctsCommonJS
.ts, .tsxES module
.jsES module when the nearest package.json has "type": "module", else CommonJS

A .js file with import statements and no "type": "module" fails with SyntaxError: … Expected an operand but found import; add the field or rename the file to .mjs.

FeatureBehavior
import lib, { a } from "./lib.cjs"module.exports is the default export, its properties are named exports
await import("./lib.cjs")Works
require("./lib.mjs")Error: require() of ES Module … not supported. (ERR_REQUIRE_ESM); use await import()
createRequire(import.meta.url)Works
import.meta.url, .filename, .dirnameWork
import.meta.main, import.meta.resolveundefined
__dirname in CommonJSWorks
__filename in the entry CommonJS file"unknown"; use module.filename. Required files get the real path.
__dirname, require in ES modulesDefined, unlike Node; do not rely on them

JSON

All of these load data.json:

import data from "./data.json" with { type: "json" };
import same from "./data.json";
const viaRequire = require("./data.json"); // CommonJS

Package exports and imports

package.json fieldimportrequire()
exports subpaths ("./feature": …)WorksWorks
exports for the package root, with mainWorksUses main
exports for the package root, no mainWorksError: Cannot find module 'pkg'
import and default conditionsWork—
A require condition listed before defaultSelected instead of default—
Unexported subpathPackage subpath is not defined by "exports" field (no code)—
imports ("#internal")TypeError: Packages imports do not define the specifier: '#internal'Error: Cannot find module '#internal'

Samples

See also

Was this page helpful?