A type checker for Nix, built on MLsub/SimpleSub — Hindley-Milner extended with subtyping, union types, and intersection types.
The goal is to have inference do as much of the work as possible but when it gets really nasty allow manually specified types through doc comments.
TLDR: try to be typescript for nix
Its currently still in progress so you might see weird type errors but has been decently usable on real projects
nix run (try without installing)
nix run github:JRMurr/tix -- inspect my-file.nixFlake (NixOS / Home Manager / nix profile)
Add tix to your flake inputs:
{
inputs.tix.url = "github:JRMurr/tix";
}Then add the package to your config, e.g. in NixOS:
# configuration.nix
{ inputs, pkgs, ... }:
{
environment.systemPackages = [
inputs.tix.packages.${pkgs.system}.default
];
}Or install imperatively with nix profile:
nix profile install github:JRMurr/tixWithout flakes (traditional NixOS / nix-env)
Add to a traditional NixOS configuration via fetchTarball:
# configuration.nix
let
tix = import (builtins.fetchTarball "https://github.com/JRMurr/tix/archive/main.tar.gz") {};
in
{
environment.systemPackages = [
tix.packages.${builtins.currentSystem}.default
];
}Pin to a specific revision for reproducibility:
let
tix = import (builtins.fetchTarball {
url = "https://github.com/JRMurr/tix/archive/<rev>.tar.gz";
sha256 = "<hash>"; # nix-prefetch-url --unpack <url>
}) {};
in
tix.packages.${builtins.currentSystem}.defaultOr install imperatively with nix-env:
nix-env -f https://github.com/JRMurr/tix/archive/main.tar.gz -iA packages.x86_64-linux.defaulttix inspect my-file.nixtix lspWorks with any editor that supports LSP. Provides hover types, completions, go-to-definition, rename, inlay hints, and more.
tix inspect <file.nix> [--stubs path/to/stubs/] [--no-default-stubs] [--config tix.toml]
tix stubs generate nixos [--flake .] [--hostname myhost] [-o nixos.tix]
tix stubs generate home-manager [--flake .] [--username jr] [-o hm.tix]
Given a Nix file like:
let
add = a: b: a + b;
result = add 1 2;
greeting = if result > 0 then "positive" else null;
in
{ inherit add result greeting; }Tix infers:
add :: int -> int -> int
result :: int
greeting :: string | null
Union types fall out naturally — if-then-else with different branch types, heterogeneous lists, etc. all just work.
Full docs (type system, stubs, configuration, internals): jrmurr.github.io/tix
To build locally:
cd docs && mdbook serve- nil — Nix LSP that does some type inference. Read over its source a lot and took some code from there to get started.
- nix-types RFC — good spec for parsing doc comments
- The Simple Essence of Algebraic Subtyping — the paper this is based on