Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to prevent types from overflowing? #102

Closed
martaver opened this issue Apr 4, 2020 · 5 comments
Closed

How to prevent types from overflowing? #102

martaver opened this issue Apr 4, 2020 · 5 comments
Assignees
Labels
question More info is requested wiki It's nice to learn stuff

Comments

@martaver
Copy link

martaver commented Apr 4, 2020

馃 Question

ts-toolbelt has been a revelation for me. I always felt typescript had great potential but fell short on tooling for its type system and ts-toolbelt delivers on that. As a result I've been more adventurous with my type programming, so thank you!

As a result of my newfound adventurousness, I find myself coming up against performance problems in type computation, resulting in poor intellisense and compiler errors such as: Type instantiation is excessively deep and possibly infinite...

Describe your question

You must have had to battle with these issues developing ts-toolbelt. Can you share with us some of your experience on how you diagnosed and solved type computation performance issues?

Specifically, I'm interested in any tools, techniques or rules of thumb you might be able to share.

Search tags, topics

typescript, type resolution, type computation, performance, type debugging

@millsp millsp self-assigned this Apr 4, 2020
@millsp millsp added question More info is requested wiki It's nice to learn stuff labels Apr 4, 2020
@millsp millsp changed the title Any suggestions on how to debug type computation performance problems? How to prevent types from overflowing? Apr 4, 2020
@millsp
Copy link
Owner

millsp commented Apr 4, 2020

Usually you don't hit these kind of errors with simple types. But this is likely to happen with recursive types, which are not officially supported type TypeScript but by ts-toolbelt instead.

TypeScript is smart and it forces you to keep a type count before it tells you Type instantiation is excessively deep and possibly infinite. This should force you to:

  • Keep your types short and neat
  • Keep your type count under 50
  • Prevent infinite loop for recursive types

Since recursive types are not directly supported by ts, it is your responsibility to make sure that your type won't overflow. In other words, it MUST have a proper terminating condition. This should be tested by you. The toolbelt enables you to do tests, check this out on the README.

If your (recursive) type overflows, it can be because:

  • Of no terminating condition
  • Type is too complex for TypeScript

It is important to note that the type system was not designed to do scripting. However, like you pointed out, there is a need for a more modular type system. It's is good to (always) ask yourself if the computation is worth it, or could it be narrowed down to something simpler? If not, then use ts-toolbelt.

So, a good rule of the thumb is: "are there more than 50 instructions within my type?"

There is one trick that I use for the recursive types described here #5. This one will prevent TS from evaluating heavy recursive types immediately, especially when they are combined together and prevent that instantiation error. You can check this out in the codebase, look for extends infer X.

@millsp millsp closed this as completed Apr 4, 2020
@martaver
Copy link
Author

martaver commented Apr 4, 2020

Wow! Thanks for the write up!

I understand the 50 instruction limit okay, it makes sense... in my case my types are complex, involving higher-kinded types but at least in theory they shouldn't be recursive.

The difficulty for me is tracing typescript's computation logic... it COULD be that I've introduced a recursion somewhere unexpectedly... but how can I discover this?

Also, what counts as a single 'instruction'...? e.g. is it a single type declaration, or a branch of logic in a type alias?

And is there a way I can evaluate the 'instruction count' for a particular type's instantiation?

Also, that defer syntax looks extremely useful. It would be useful to have a 'recipe book' of these kind of manipulation that force the typescript compiler to do something 'out of the ordinary'... Compute, Clean and Cast are good example also.

@millsp
Copy link
Owner

millsp commented Apr 4, 2020

I agree, it is difficult to trace those errors. You can either start compiling your own version of TypeScript so that you can display useful info... Or, you can use the --extendedDiagnostics flag which will give you a somewhat clearer understanding of how your type is behaving. You'll be able to see your type count there.

What I call a single instruction is basically either a (naked) extends clause, mapped type, or simply a return. So if you'd nest such utilities in a parent type, it counts the branches of logic within it too... And if it hits that count before finishing, then it throws you that message. You see, it's your whole type that has to stay lightweight, all your logic branches within it.

And it's not always easy. Sometimes, you'd be better off rewriting the whole thing from scratch rather than using ts-toolbelt, just to save yourself from that count. A simple approach is to disable some of your logic with dummy data, then see which parts are under-performing. But maybe you're doing something wrong, and you can as well post your type in another question.

With the type system running on top of JavaScript, we clearly lose performance. IMHO, we would have been better off if the TS server had native performance so that we could have a more scripted (and faster) type system... But maybe, as TypeScript grows, this will become more obvious in the future.

@martaver
Copy link
Author

martaver commented Apr 4, 2020

I also noticed that in 3.9.0, my excessively deep type error goes away... I'm speculating that this is to do with the optimisations they introduced (https://devblogs.microsoft.com/typescript/announcing-typescript-3-9-beta/#speed-improvements)

Any insight into whether the new version changes the game?

Edit: to respond to your last post (thank you) the last round of optimisations were inspired by the poor performance of common tools like styled-components, which are made useful by their full-featured type APIs... maybe this is a sign they are starting to take the performance of the type system more seriously.

@millsp
Copy link
Owner

millsp commented Apr 4, 2020

Thanks for the info, I'm glad they've put effort into it :)

Repository owner locked and limited conversation to collaborators Feb 2, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
question More info is requested wiki It's nice to learn stuff
Projects
None yet
Development

No branches or pull requests

2 participants