npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

typeflowjs

v0.0.2

Published

Typed JSON transformations, checked at compile time. Declarative .typeflow mapping files with TypeScript-native typing.

Downloads

38

Readme

Typeflow

Typed JSON transformations. Checked at compile time.

Typeflow is a declarative mapping language for JSON with first-class TypeScript typing — validated paths, inferred output types, and compile-time errors for your data transformations.

▶ Try it in the Playground · Documentation

You've written this function a hundred times: take the API's JSON, reshape it into the type your app wants. It's boring, it's error-prone, and when the API changes, TypeScript can't tell you which of your forty mapping functions just broke. JSONata and jq make the transformation declarative — but invisible to your compiler. Typeflow makes it declarative and typed: paths autocomplete, typos are compile errors, output types are inferred, and your mappings are artifacts you can test, diff, and trust.

Input JSON shape → .typeflow mapping file → Typed output shape

A 30-second look

user.typeflow — the mapping body mirrors the output shape; leaves are expressions over the input:

input user: ApiUser from "./user-types"

map {
  id: user.id,
  fullName: user.firstName + " " + user.lastName,
  isAdmin: user.role == "admin",
  email: user.contact?.email ?? "unknown",
  activeTags: user.labels[active].name,
  address: user.address -> {
    city: city,
    country: country ?? "unknown",
  },
}

Typo in a path? That's a compile error, not a production incident:

user.typeflow:4:11 - error TF2002: Property 'emial' does not exist on type
'{ email: string; contact?: { phone: string } }'. Did you mean 'email'?

4    mail: u.emial,
             ~~~~~

user.typeflow:5:20 - error TF2003: Object is possibly 'undefined'.

5    phone: u.contact.phone,
                      ~~~~~
  hint: Use the optional access operator: '?.phone', or provide a default with '??'.

And the output type is inferred, not hand-written:

$ typeflow infer user.typeflow
{
  id: number;
  fullName: string;
  isAdmin: boolean;
  email: string;
  activeTags: string[];
  address: { city: string; country: string };
}

How it works

  1. Bind the input. input user: ApiUser from "./user-types" extracts the type through the TypeScript compiler API (inline structural declarations work too).
  2. Check the mapping. Every path is validated against the input type. Optional segments require ?. or a ?? default — and a default removes the optionality from the output type.
  3. Infer the output. typeflow types emits a user.d.typeflow.ts declaration, so import mapUser from "./user.typeflow" is fully typed (via TypeScript's allowArbitraryExtensions).
  4. Run it anywhere. Compiled mappings are JSON-serializable and executed by a small, deterministic, dependency-free interpreter — Node, Bun, browsers, CI.

Quick start

$ bun add -d @typeflowjs/cli                                # the `typeflow` binary (github.com/typeflow/cli)
$ bunx typeflow init                                       # scaffold an example mapping
$ bunx typeflow check                                       # tsc-style diagnostics
$ bunx typeflow infer user.typeflow                         # print the inferred output type
$ bunx typeflow types                                       # generate .d.typeflow.ts declarations
$ bunx typeflow run user.typeflow --input data.json
$ bunx typeflow watch                                       # re-check + regenerate on change
$ bunx typeflow fmt                                          # rewrite mappings in canonical form
$ bunx typeflow convert mapping.jsonata --type jsonata      # migrate from jq/JSONata, in parallel across files

Enable typed imports in tsconfig.json:

{ "compilerOptions": { "allowArbitraryExtensions": true } }

Programmatic API

Only using it from code? Skip the CLI package — typeflowjs alone is enough:

$ bun add -d typeflowjs
import { loadTypeflowMapping } from 'typeflowjs';

const mapUser = await loadTypeflowMapping('./user.typeflow');
const view = mapUser(apiResponse);

Direct imports

With @typeflowjs/plugin, skip even that — import the mapping file itself (node --import @typeflowjs/plugin/register, or preload = ["@typeflowjs/plugin/bun"] in bunfig.toml; require() works too):

import mapUser from './user.typeflow'; // typed via the .d.typeflow.ts sidecar

const view = mapUser(apiResponse);

IDE support

Syntax highlighting, inline diagnostics, and completion on input-bound fields — for VS Code and JetBrains IDEs (IntelliJ/WebStorm/…), each in its own repo. Both shell out to the typeflow CLI rather than bundling the compiler, so they always match whatever version is installed in your project. Build from source until they're on their respective marketplaces (each repo's README.md has build steps).

The language (v0.1)

| Feature | Example | | ------------------ | ----------------------------------------------------------------- | | Path access | user.address.city | | Optional access | user.contact?.email (required when the path is optional) | | Defaults | country ?? "unknown" (removes optionality from the output type) | | Computed fields | user.firstName + " " + user.lastName | | Conditionals | user.n > 10 ? "big" : "small" | | Array filtering | user.labels[active] (predicate in element scope) | | Array indexing | user.labels[0] (typed as element \| undefined) | | Array path mapping | user.labels.name → string[] | | Projection | user.items -> { label: upper(name) } | | Functions | upper, lower, trim, count, sum, join | | Comparisons | == != < <= > >= (no-overlap comparisons are flagged) |

Deliberately not a programming language: no loops, no mutation, no recursion, no I/O, no inline lambdas. Mappings are deterministic and sandboxable by construction.

Why not …?

| | Typeflow | JSONata | jq | Zod | Plain TS function | | ----------------------------------- | -------- | ------- | --- | --------------- | ----------------- | | Declarative transformation | ✅ | ✅ | ✅ | ❌ (validation) | ❌ | | Input paths statically validated | ✅ | ❌ | ❌ | n/a | ✅ | | Output type inferred | ✅ | ❌ | ❌ | ⚠️ declared | ✅ | | Serializable / sandboxable artifact | ✅ | ✅ | ✅ | ❌ | ❌ | | Deterministic by design | ✅ | ⚠️ | ✅ | n/a | ❌ |

Zod is a natural input to Typeflow, not a competitor: Zod answers "is this X?"; Typeflow answers "how does X become Y, and is that conversion sound?"

Monorepo layout

| Package | Responsibility | | ------------------- | ----------------------------------------------------------------------------- | | typeflowjs (root) | Compiler, type checker, runtime, TS adapter, formatter. Zero deps | | apps/benchmarks | Runtime benchmarks vs jq/JSONata (private, powers the docs /benchmark page) |

apps/benchmarks has its own package.json; see its README.md for build steps and why it isn't a declared Bun workspace member. Everything else that used to live under apps/* has moved to its own repo, since none of it shares source with the monorepo: typeflow/cli (@typeflowjs/cli — the typeflow binary), typeflow/plugin-typescript (@typeflowjs/plugin — import .typeflow files directly), and the VS Code and JetBrains IDE plugins, the converters that migrate mappings from other JSON mapping languages onto Typeflow, and the documentation site: typeflow/plugin-vscode, typeflow/plugin-jetbrains, typeflow/converters and typeflow/docs. All of them depend on the published typeflowjs package (@typeflowjs/cli and @typeflowjs/converters as regular/optional dependencies, @typeflowjs/plugin as a peer dependency since it compiles mappings in the consumer's own process) instead of reaching into src/ directly.

Development

$ bun install                    # root deps
$ bun test                       # 133 tests across parser, compiler, runtime, adapter, e2e
$ bun run typecheck              # generate example declarations + tsc --noEmit
$ bun run demo                   # compile + run examples/api-response

apps/benchmarks needs its own first-time install (Bun workspaces aren't used):

$ bun install --cwd apps/benchmarks

Roadmap

  • v0.1 (this) — core language, TS adapter, inference, .d.typeflow.ts emission, CLI, formatter, jq/JSONata converter, VS Code + JetBrains support.
  • v0.5 — language server (real diagnostics/completion instead of shelling out to the CLI), Zod/JSON Schema adapters, fragments, match on discriminated unions, fixtures, contract mode (declared output).
  • v1.0 — frozen grammar + conformance suite, OpenAPI adapter, execution limits, Vite plugin.

Pre-1.0, syntax and APIs are unstable by design.

License

MIT © Thomas Farineau