To your point @tennyson, the DSL approach you sketched out is very similar to the mental model of my POC – both model nix in TS and also generate types for the common APIs.
And @pyrox, agree completely that any such system needs full nix interop and, eventually, first-class language support (like stack traces). That’s table-stakes for any serious tool.
My hunch is that these two ideas aren’t in conflict: we can (and must) have both. Let’s figure out how a TypeScript DSL could cover the entire surface area of Nix.
This gets to the core of the TypeScript angle. Right now a developer needs to jump over multiple hurdles to effectively use Nix:
Nix (the language): the syntax
Nix (the standard library): lib and other essential utilities
Nix (the philosophy): derivations, build concepts, etc.
nixpkgs conventions: e.g., how to override packages
We’ve set up an incredibly difficult on-ramp for developers.
That begs the million dollar question: how can we re-use familiar interfaces to remove the unessential hurdles while keeping both Nix’s essence (the philosophy) and access to the existing ecosystem
Well, yes, but this still only solves the simplest cases and in my experience TS type system tends to fall over pretty quickly if you try to do inference on non-trivial recursive types and you end up with either any or never — granted, I haven’t done any serious type trickery in a few years, so maybe the situation had improved. So I imagine if you’d try to integrate with the NixOS module system the way it works (by computing fixpoints) it’ll quickly devolve into type-level trickery that soon falls apart. And I don’t think that a typical user who is resistant to learning a new language, will be happy with the arcane type-level things going on — if it works, then error messages will be atrocious (YMMV but worse than Nix stack traces),
Not being able to support all of the usual nix-isms from TS will effectively mean that either:
we will end up with two divergent module ecosystems,
people will have to end up learning Nix anyway when the training wheels don’t suffice anymore.
And say we drop typing from the scope as not practical — which I think is actually one of the bigger issues Nix IMO has, though more from the discoverability angle than type-safety angle — then all we end up is getting a syntax sugar layer over Nix, where you have to sometimes thunk things yourself into lambdas that you wouldn’t have to in Nix (there’s a possibility that JS circular imports might help here to recover laziness at a module boundary, when not constrained by TS limtations, but unsure)
So YMMV, but for me all this brings is only the vaguest sense of familiarity in return for introducing an abstraction layers to paper over the impedance mismatch. To me it feels like it’s way better to invest into improving Nix-the-language DX — for example by improving documentation and not letting things like this PR languish for months — than trying to put fancy clothes over it that you’d have to take off when you have to get dirty anyway. And I think that ultimately the best solution in the long term is waiting for Nickel to get an effect system, so it can be easily tied into the way NixCpp works.
So at least my answer to that is — keep Nix-the-lang, fix DX, fix DX, fix DX, improve onboarding and documentation, ???, PROFIT!
Also, if TypeScript is a must for some reason, then maybe it makes more sense to use something that was built ground up for it, like https://brioche.dev/? Maybe the store layer work Tomberek and Ericson mentioned could at some point allow for a common underlying store (that or tvix/snix CA store work)?