Manual TypeScript

TypeScript

elements man typescript Read as markdown

Elements is the first build tool to compile the TypeScript compiler, the Go implementation, directly into its own binary. Type checking is a phase of the build, running in the same process against the same in-memory source graph as compilation, so a save is checked, compiled, and hot reloaded in a few milliseconds. Both targets are checked, the browser and the server, each against the types it actually has.

One program, one graph

Every source in a project has a version derived from its content and the versions of everything it imports. The checker consults that version like every other phase of the build: a file whose version has not moved is not rechecked, and a change deep in the graph rechecks exactly the cone that depends on it. The same graph drives the build cache, the test runner, hot reload, and the deploy, so type checking, compilation, and release agree on one version of every file.

Checking runs incrementally inside the build loop, on the same thread that watches your files. A single-file save typically type checks, compiles, and hot reloads in a few milliseconds.

The Elements languages are TypeScript

Elements HTML templates and JSOC config files are implemented on top of the TypeScript compiler's own binder, symbol table, and checker, not beside them. A template attribute is a TypeScript declaration. A template name resolves through the normal symbol table. The expressions inside {} are checked against the surrounding scope by the same checker that checks a .ts file, with the same error messages. There is no second type system to learn, and no seam where TypeScript ends and Elements begins.

<Comment (comment: Comment, private editing: boolean = false)>
  <p>{comment.text.toUpperCase()}</p>
  <p>{comment.txet}</p>   <!-- error: Property 'txet' does not exist on type 'Comment' -->
</Comment>

Two targets, one source

A file is checked for every target it reaches. Server code sees Node's types and the server half of @elements/app; browser-reachable code sees the DOM and the browser half. A server-only call such as sql() made from code the browser can reach is a compile error at the call site, so a query or a secret cannot reach the browser by accident. You do not annotate anything; the compiler follows the call graph. See rpc for the boundary and async for how sync-style calls type check without await.

Options

TypeScript options live under build.typescript in config.jsoc, a flat mirror of tsconfig's compilerOptions limited to the options Elements honors. Strict checking is on. There is no tsconfig.json in an Elements project and you should not add one.

build: {
  typescript: {
    lib: ["es2022", "dom"],
  },
},

Full config syntax: config.

Editors

The project server speaks the Language Server Protocol, so editors get completions, diagnostics, go-to-definition, and rename for .ts files, HTML templates, and JSOC alike, from the same checker the build uses. It replaces tsserver. VS Code and its derivatives get this automatically; the extension is installed when you install Elements. For vim and neovim see vim.

Diagnostics

Type errors are build errors. They appear in elements build, in elements build -json as diagnostics with a path and a 1-based loc, and in the editor, all from one check. A build with a type error anywhere does not release, and neither do the tests it would have gated. See build.

Related

  • build: the loop the checker runs inside.
  • html: the template language the checker understands.
  • config: build.typescript.
  • async: the sync-style transform and how it types.