Make twoslash (\\=>) type validation agnostic of union order#1347
Merged
sindresorhus merged 9 commits intomainfrom Feb 7, 2026
Merged
Conversation
4873b12 to
6156ae3
Compare
Contributor
6156ae3 to
c7f0d38
Compare
som-sm
commented
Feb 7, 2026
Comment on lines
+87
to
+88
| incorrectTwoslashType: 'Expected twoslash comment to be: {{expectedComment}}, but found: {{actualComment}}', | ||
| incorrectTwoslashFormat: 'Expected twoslash comment to be: {{expectedComment}}, but found: {{actualComment}}', |
Collaborator
Author
There was a problem hiding this comment.
While the error message is the same for both cases, having two different error types helps in writing tests in a more controlled fashion.
Owner
|
Great to have this resolved 🙏 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Union order in TS is not guaranteed to be stable and can change due to completely unrelated changes. This beautiful example illustrates this idea clearly.
Here's another example:
Playground: https://tsplay.dev/weGQ1m
Notice how the order of
T1union changes even though the implementation ofArrayElementitself is unchanged.This is problematic for our twoslash validator lint rule because it currently doesn't perform an order agnostic type validation. As a result, changes in one part of the codebase can cause twoslash types to fail in completely unrelated locations. And, this also makes the tests for the lint rule flaky.
Working
Currently, this lint rule performs two validations:
Validates that the specified twoslash type is correct.
Validates that the specified twoslash type is formatted correctly (for example, use of single quotes, spacing, indentation, etc.).
At the moment, both these validations are performed as part of a single check. The type returned by the
getQuickInfoAtPositionAPI is converted into a properly formatted twoslash comment and then compared directly with the specified twoslash comment. This allows correctness and formatting to be validated in one pass.With the updated implementation, however, these two validations can no longer be reliably performed in a single check. As a result, they are now handled in two steps. Below is a breakdown of the new approach.
Updated validation flow
Normalize and compare types
Both the specified type and the actual type are normalized, and their normalized forms are compared. This ensures that validation does not depend on union order. For example, all of the following are treated as valid:
If validation fails at this stage, the fixer suggests the normalized form of the actual type. While it could suggest the raw actual type and defer formatting to the next step, using the normalized form felt more reasonable, as it avoids the need for two separate fixes.
Validate formatting
Once the specified type is confirmed to be correct, we then validate its formatting.
This step also enforces that numbers in unions are sorted in ascending order. So, numbers in unions cannot appear in any arbitrary order.
If this feels too restrictive, this requirement can be easily removed in the future.
NOTE: Enforcing numeric ordering does not reintroduce the original issue of union-order dependence. The lint rule remains agnostic to union order because this check runs in a separate pass and is purely a formatting validation.
This PR also fixes the following issue:
In unions containing both numbers and non-numbers, the intent was to sort only the numbers while keeping the position of non-numbers intact. However, that wasn't happening correctly. For example:
The above twoslash type is considered valid, but it actually is not because the numbers are not sorted. The correct twoslash type in this case would be:
Credits to @taiyakihitotsu for pointing this out!
Related: