TypeNix: Full typing for Nix based on TypeScript

TypeNix applies the full TypeScript type system to .nix files - hover types, go-to-definition, real type errors, directly in your editor.

Kooha-2026-03-10-08-38-54_2x

How it works: instead of building a new checker for Nix, it maps tree-sitter-nix’s AST directly to TypeScript AST nodes. The standard TS binder, type checker and LSP work almost unchanged – they never know they’re looking at Nix.

What works:

  • Hover, go-to-definition, autocomplete on builtins, lib, mkDerivation, much of main pkgs attrset
  • Runs on all 42K nixpkgs files in 13s
  • And the fun part: Fixed-point patterns (makeExtensible, finalAttrs): typed via transform to a TS class with late this binding

It’s an early POC – nixpkgs typing is partial (TypeScript defaults to any in many places) but the general approach is robust at scale. PRs welcome.

Try it out:

  • Directly (tsc equivalent): nix run github:ryanrasti/typenix -- --noEmit
  • Install to VSCode: code --install-extension $(nix build github:ryanrasti/typenix#vscode-extension --print-out-paths)/typenix.vsix

Github: GitHub - ryanrasti/typenix: Full typing for Nix based on TypeScript · GitHub

32 Likes

That’s impressive; are you experimenting with caching and such to make this usable from LSP?

Frankly, I’ve never gotten on with typescript (even having an any type, let alone defaulting to it, makes it pretty much unusable), but as far as upgrading nix backwards-compatibly goes, this is very cool.

Have you considered integrating with the RFC 145 doc comments?

1 Like

That’s impressive; are you experimenting with caching and such to make this usable from LSP?

It actually already has both an LSP and caching, since it piggybacks on TypeScript (added a gif to the original post, take a look!)

Frankly, I’ve never gotten on with typescript (even having an any type, let alone defaulting to it, makes it pretty much unusable)

Fair, default any is a limitation of this PoC. (Once enough of pkgs have anotations, TypeScript actually has a setting where you can disable implicit any, so it should be robust!)

Have you considered integrating with the RFC 145 doc comments?

Great next step and should be achievable but haven’t looked into it yet.

3 Likes

Yeah, and precisely that is usually why these uptyping efforts ultimately fail to accomplish their goals IME. Disabling any is that dangling carrot you can never quite reach. But it’s a very cool attempt, hopefully this one goes well :slight_smile:

1 Like

Is module system support/typegen for this on the radar? I would totally use it if it is! (might even just set it up without it because i like autocomplete that does not rely on nix internals, as i use Lix)

3 Likes

Yes module support is on the radar – PRs very welcome if you want to take a crack at it. My intuition is that it is largely adding type annotations to various .nix files.

1 Like

so … you reinvented the Volar.js?

No; this enhances nix code with type information, which it doesn’t currently have.

The project you link would be useful in addition to this project, but the goals of the two are completely unrelated.

I think there might be a misunderstanding — Volar.js is not a language server itself, but a framework for building language servers that map non-TS languages to TypeScript’s type checker and LSP. Vue, Astro, and MDX all use it for exactly this purpose.

Typenix’s approach (tree-sitter AST → TS AST → reuse TS binder/checker/LSP) is quite close to what Volar provides as infrastructure. So my question was less about the typing goal and more about the implementation strategy — it seems like Volar could have been a useful foundation here.

1 Like

Interesting, thanks for bringing up Volar.js. From what you say yes sounds like a very similar idea. I wasn’t able to find out much from their docs about the exact approach.

A couple of things to point out:

  • The hard parts of TypeNix: AST conversion, source mapping, semantic differences between Nix/TS (laziness/fixed point handling), which would have to be done regardless
  • TypeNix is built on tsgo in an attempt to future-proof (i.e., the next version of TypeScript – TS 7) while it looks like Volar is still using JavaScript-based TypeScript

That said, good eye – it sounds like the core insight of piggy-packing on TS is the same.

3 Likes

Amazing work, can’t wait to try this.

How would you recommend that I contribute flake-parts typing as an exercise?

Do you have any thoughts on Nix with gradual typing beyond type annotations in comments?

Do I understand correctly that you encode lambdas as classes because many lambdas reflect some kind of module which does map nicely to a class?

There is a Tweag post from 2017: Typing Nix that describes record / row typing, which is a little more functional than the class-like typing I understand from your readme. Do you think the TS typechecker is a good match for gradual row types? (I’m not familiar enough with what TypeScript types are capable of, and when their theoretical foundation fall short.)

2 Likes

Amazing work, can’t wait to try this.

Thank you!

How would you recommend that I contribute flake-parts typing as an exercise?

I’d recommend first typing the flake manually. There are # @ts: style annotations right now that you can type individual parameters with. Perhaps declarations can then be extracted into a .d.ts. The best patterns for how to type flakes/flake dependencies is still a WiP – something to iterate on.

Do you have any thoughts on Nix with gradual typing beyond type annotations in comments?

TypeScript proved the model for JavaScript: adding a few special syntax elements that have no effect at runtime (only used for type checking). I think the same approach could be adopted for Nix, the hard part is agreeing on what exactly that syntax would look like.

Do I understand correctly that you encode lambdas as classes because many lambdas reflect some kind of module which does map nicely to a class?

Kind of – most Nix constructs map 1:1 cleanly to TypeScript, including general lambdas (they map to arrow functions).

Where the class comes in is for self-referential fixed point like extends.

Do you think the TS typechecker is a good match for gradual row types?

Yes absolutely. JavaScript also has anonymous records and TS has extremely good tools for typing them.

1 Like