Live data from Hacker News

Extreme explorations of TypeScript's type system

learningtypescript.com

11–20 of 64 posts

Re: Extreme explorations of TypeScript's type system

#11

Are there (m)any other languages with type systems as flexible and powerful as Typescript's?

I would guess that all languages with Turing complete typesystems would be technically equally powerful. I think Typescript supports more useful behaviors out of the box.

Re: Extreme explorations of TypeScript's type system

#12
post #6
post #5

To try and limit one's use of operations on types, as suggested in the article, is not really great advice in my opinion. Sure, you would not want to actually implement and use a VM in types, but distilling rules about a program into types and then deriving the actual interfaces and signatures from those rules with operations on types? That's quite powerful. TypeScript's type annotations are really a DSL embedded int…

I think it depends how far you go: if you start encoding rules into the type system that are undecidable then you can quickly run into trouble.

To me its about readability. I agree that operations on types generally are a good thing because I find them more readable. Not using operations I've found leads to many very specific types which are hard to read and understand from the devs perspective.

Re: Extreme explorations of TypeScript's type system

#13

TypeScript's type system is Turing Complete: meaning it has conditional branching (conditional types) and works with an arbitrary huge amount of memory. As a result, you can use the type system as its own programming language complete with variables, functions, and recursion. This blog post is a starting list of a bunch of the shenanigans TypeScript developers have pushed the type system to be able to do.

It also makes static checking undecidable in pathological cases. I know Idris has this problem as well; they work around it by skipping partial functions in types, so you end up with "total" and "partial" programs where only the former are completely typechecked proofs.

Re: Extreme explorations of TypeScript's type system

#14
post #5

To try and limit one's use of operations on types, as suggested in the article, is not really great advice in my opinion. Sure, you would not want to actually implement and use a VM in types, but distilling rules about a program into types and then deriving the actual interfaces and signatures from those rules with operations on types? That's quite powerful. TypeScript's type annotations are really a DSL embedded int…

> TypeScript's type annotations are really a DSL embedded into JavaScript. And they can, and, depending on the problem at hand, should be treated as such.

I think this is the key. If treated as you describe, meaning the advanced types are well-written, well-documented, and well unit-tested as if they are "true" code, then using them shouldn't be too much of an issue.

However, I think people often just assume that the types aren't "real" code and thus the normal concepts of good software engineering don't apply and type monstrosities which nobody can understand result.

Imagine if this code[0] wasn't well-documented, fairly clearly written, and also tested. It would definitely be a liability in a codebase.

In addition, the rules of how advanced TypeScript concepts work can be quite nuanced and not always extremely well defined, so you can end up in situations where nobody even _really_ understands why some crazy type works.

[0]: https://github.com/sindresorhus/type-fest/blob/2f418dbbb6182...

Re: Extreme explorations of TypeScript's type system

#15

Are there (m)any other languages with type systems as flexible and powerful as Typescript's?

I would guess that all languages with Turing complete typesystems would be technically equally powerful. I think Typescript supports more useful behaviors out of the box.

Equally computationally powerful, but not necessarily equally powerful as type systems. "X is Turing complete" means that it can compute the same set of computations as any other Turing complete system, but it does not mean that it can accept inputs and produce results in an encoding relevant to what you're trying to do.

Re: Extreme explorations of TypeScript's type system

#16
> If you do find a need to use type operations, please—for the sake of any developer who has to read your code, including a future you—try to keep them to a minimum if possible. Use readable names that help readers understand the code as they read it. Leave descriptive comments for anything you think future readers might struggle with.

Also, as you start getting complicated logic in your types, you need to test your types; make sure they admit things they should admit and reject things that they should reject. Ideally these tests can also serve some role as examples for your documentation.

Re: Extreme explorations of TypeScript's type system

#17

> If you do find a need to use type operations, please—for the sake of any developer who has to read your code, including a future you—try to keep them to a minimum if possible. Use readable names that help readers understand the code as they read it. Leave descriptive comments for anything you think future readers might struggle with. Also, as you start getting complicated logic in your types, you need to test your…

@ts-expect-error is useful for this

Re: Extreme explorations of TypeScript's type system

#18

> If you do find a need to use type operations, please—for the sake of any developer who has to read your code, including a future you—try to keep them to a minimum if possible. Use readable names that help readers understand the code as they read it. Leave descriptive comments for anything you think future readers might struggle with. Also, as you start getting complicated logic in your types, you need to test your…

We do a _lot_ of this in the Redux library repos (examples: [0] [1] [2] ). We have some incredibly complicated types in our libraries, and we have a bunch of type tests to confirm expected behavior.

Generally, these can just be some TS files that get compiled with `tsc`, but it helps to have a bunch of type-level assertions about expected types.

I actually recently gave a talk on "Lessons Learned Maintaining TS Libraries" [3], and had a couple slides covering the value of type tests and some techniques.

[0] Redux Toolkit's `createSlice`: https://github.com/reduxjs/redux-toolkit/blob/9e24958e6146cd...

[1] Reselect's `createSelector`: https://github.com/reduxjs/reselect/blob/f53eb41d76da0ea5897...

[2] React-Redux's `connect`: https://github.com/reduxjs/react-redux/blob/720f0ba79236cdc3...

[3] https://blog.isquaredsoftware.com/2022/05/presentations-ts-l...

Re: Extreme explorations of TypeScript's type system

#20

TypeScript's type system is Turing Complete: meaning it has conditional branching (conditional types) and works with an arbitrary huge amount of memory. As a result, you can use the type system as its own programming language complete with variables, functions, and recursion. This blog post is a starting list of a bunch of the shenanigans TypeScript developers have pushed the type system to be able to do.

That's not the meaning of turing completeness, just an implication of the space hierarchy theorems. There are systems that also have branching and unbounded memory, but are not turing complete. Context free grammars for example.

Turing completeness means for TS that for every computable function, there is a TS type that can compute that function (if TS wouldn't limit the recursion depth).

Post reply on HN