mxsdev / ts-type-explorer

VSCode Extension & utilities for exploring TypeScript type information
https://marketplace.visualstudio.com/items?itemName=mxsdev.typescript-explorer&ssr=false
161 stars 4 forks source link

Lazy evaluation #36

Open b0o opened 1 year ago

b0o commented 1 year ago

While exploring complex types, I often hit the recursion limit, and need to perform the workaround I described in #35 of creating a dummy type.

Would it be possible to lazily evaluate types as the user expands nodes in the ts-type-explorer tree, and get rid of the recursion limit?

For example, when you first open ts-type-explorer, only the first level of the tree is visible. Rather than evaluating all branches of the tree until the recursion limit is reached, could you only evaluate the visible nodes? That way the user should be able to continue expanding nodes without hitting an arbitrary depth limit.

mxsdev commented 1 year ago

Hey, so lazy evaluation is supported, but only on symbols which have identifiable locations.

So, for instance, the following type has lazy evaluation, and will not hit the recursion depth:

type Nested = { a: { b: { c: { d: { e: { f: { g: { h: { i: { j: true } } } } } } } } } }

The same is true for recursive types:

type Nested = { a: Nested }

However, the following will not:

type Nested = { a: { b: { c: { d: { e: { f: { g: { h: { i: { j: T } } } } } } } } } }
type InstantiatedNested = Nested<true>

The problem here is that the tsserver is "volatile," in the sense that it can restart at any time. So there's no way to maintain state on tsserver, or keep track of types using their IDs.

So there is a distinction between types that have symbols associated with them (and therefore have trackable locations that can be lazily resolved), and types that are "generated." Unfortunately generated types cannot be easily retroactively resolved.

I guess one approach would be to keep track of the "root" symbol and information for how to walk the type tree to get back to the desired node. But I don't see a great way to implement this, at least not in a performant way...