This is my "lodash for types" project. It supports integer division for up to 2^64, for example. It has over 200 composable utility types.
This is my "lodash for types" project. It supports integer division for up to 2^64, for example. It has over 200 composable utility types.
lodash does come to mind in fact. The last few shops where I've worked use a very small subset of lodash utilities and ignore most of the library. Their documentation is terse so it's often easier to just write your own code that is longer but more readable to the average engineer.
These projects are interesting in an amusing "oh look, another Turing complete type system" way, for the author to gain expertise, and as something to highlight in CVs and to chat about during interviews. But other than that, I would never actually choose to use any of this in a real-world project. Depending on the stability of this API (TPI?), and subjecting colleagues to esoteric libraries would be a nightmare to maintain and support.
This can be frustrating in the moment sometimes, but other times a type can do two really powerful things:
1. prevent someone you’ve never spoken to from doing something legitimately dangerous 2. provide browsable documentation about the constraint its enforcing and how other places in the code resolve the constraint.
It doesn’t always work out that way, sure, but that’s the ideal types are striving for.
It doesn't provide "browsable documentation". It provides complex unreadable types that you have to painstakingly manually "compile" in your head to figure out what the hell is going on
- types are not documentation
- tests are not documentation
- code is not documentation
Note that there are very few languages that have those kinds of types. Usually it's enums and union types that usually tell you nothing about where to get those ranges, why those ranges exactly, or what those ranges mean.
Literally right now I'm looking at a GraphQL schema that tells me that for a collection of lists of data it returns the following list types: Generic, GenericV2, Onboarding, OnboardingActive... That's it. Actual call returns only a few of those with no apparent difference in actual data.
It is typed though.
You don't have to compile in your head; you can declare a variable or assignment with some type property and see where an error is thrown.
I've seen quite a few cases where IDE's type expansion (whether on hover or in type errors) would result in a dozen lines of nested types. Worse than no documentation at all.
(And, of course, as with other source code, illegibility implies more documentation needed. For type systems in particular, I think people tend to under-declare their types [i.e. they'll do "Record<KeyType, Array<{name: string, address: string}>" instead of "Record<KeyType, EmployeeRecords>"], which gives the compiler fewer hooks to shortcut talking about a complex type).
There is one thing consistently true about type systems that frustrates me: I write in procedural code all day, but basically all type systems are functional code. It is frustrating to have to spin my reasoning around to attack a problem in a different language structure when I've been doing straight-line statement-by-statement all day. I don't have a solution to that, but I observe the challenge.
None of these actions make types documentation. The necessity to do this makes them a hindrance at best.
> I think people tend to under-declare their types [i.e. they'll do "Record<KeyType, Array<{name: string, address: string}>" instead of "Record<KeyType, EmployeeRecords>"
Oh god, so true :)
By the same argument, code isn't documentation. And yet it is; all manner of style guides will tell us "Document the non-obvious, but let the code speak for itself when it's obvious." The challenge, of course, is obviousness is subjective. And I've definitely encountered type stacks where the author thought they were being perfectly clear and the reader didn't. But that makes it no different from other forms of docs.
I think the truth is types (and code) are a little of both documentation and implementation. After all, if code alone were sufficient, we'd just be hand-rolling 1 and 0 patterns to tickle the CPU directly; the existence of programming languages themselves are to bridge the gap between the minimum information a computer needs and human comprehension of what we're trying to get the computer to do.
(Whether types are docs at all, let me put it this way: every modern style guide I've found for languages where strong static typing isn't available declares I have to put the types in the documentation, especially for function calls and the like. That seems to heavily imply that types are a form of auto-checked documentation).
It isn't.
> all manner of style guides will tell us
A lie parroted ad infinitum doesn't make it truth.
Comments clearly aren't code, in the sense that they're a specific form in a language dedicated to being thrown out by the compiler / interpreter / etc (usually; I'm handwaving over the metaprogramming approaches like Doxygen that parse comments). But there's a reason we name variables `time_to_completion` instead of just `a`, or name functions (or have functions instead of jump pointers crammed into global variables), etc.
That's a pretty [good definition I think](https://en.wikipedia.org/wiki/Documentation). I also think a type does provide explanation and instructions about how to use typed code. So, I think by definition, types are undeniably documentation.
The type vs. no type argument is basically: what's the cutoff line for constraints that are worth encoding as types or not?
In cases where the type system can encode the invariants you care about, it can be worth the extra complexity so that you have code that has compiler enforced correctness (at least in some aspects). Of course, you can't do this for any invariant in a given type system (eg lifetimes are not representable in Java). When it is possible though, debugging a type system has the advantage that it's done on your local machine, away from prod.
It would be funny to see web servers running the typescript compiler (type checker) instead of a JS runtime, though.
There is a project I'm working on to eliminate the latter bit - ideally, a way to represent these complex types with "zero type-level code"