Skip to content
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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate type tests to TSTyche #2725

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

mrazauskas
Copy link
Contributor

@mrazauskas mrazauskas commented Feb 23, 2024

Thanks for using jest-runner-tsd and tsd-lite to test types. I am was maintaining tsd-lite and helping with the runner too.

Just wanted to let you know that tsd-lite got deprecated. It is replaced with TSTyche, a mighty type testing tool that I was developing for two years.

The problem is that architecture of tsd is very limiting. Without maintaining forked tsd-lite it was not possible to upgrade TypeScript in Jest repo. tsd-lite was temporary solution to get unblocked and to learn more about type testing.

I was contributing type tests to Jest repo for some time. There are around 1200 assertions. At this scale it was a pain debugging types. So I went on researching and building TSTyche. Similar to tsd, it compares types programmatically, but the rest is different.

I just try to explain that TSTyche is build to work at any scale and to last for year. That's why I would like to recommend to use it in your project.

Currently TSTyche is used by Immutable.js, Jest, Redwood and few more smaller project (including my own packages).

Repo: https://github.com/tstyche/tstyche
Documentation: https://tstyche.org


TSTyche has test() and describe() helpers which support run mode flags like .only, .skip or .todo. These are priceless if you have to debug something. By the way, additionally there are expect.fail expect.only or expect.skip.

--only and --skip can be set from the command line: tstyche useful-types --only DeepPartial.

It has expect style assertions which look familiar. An expression or a type can be passed on both sides of an assertion. This means that TSTyche is able to compare two types directly. There is no need to create intermediate values.

Testing on several versions of TypeScript is supported: tstyche --target 4.9,current. This command would use TypeScript 4.9 and the one from node_modules (the current).

By default TSTyche uses typescript from node_modules. There is no need to install patched TypeScript package like @tsd/typescript. The install size of TSTyche is under 200kB. It has no dependencies.

TSTyche is fast. Just give it a spin.

And there is much more.


Curious what you think.

it('marks properties as optional recursively', () => {
expect<DeepPartial<Base>>().type.toMatch<{}>();
expect<DeepPartial<Base>>().type.toMatch<{optional?: string}>();
expect<DeepPartial<Base>>().type.toMatch<{required?: string}>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.toMatch() is used to check partial matching, otherwise .toEqual() is used. .toEqual() would not work here because the type is recursive.

Comment on lines 108 to 110
expect<DeepPartial<State>>().type.toMatch<{
readonly preset?: {} | undefined;
}>();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.toMatch() checks readonly modifiers strictly.

Comment on lines -139 to -143
* should not be able to add undefined, need to fix this
*/
expectNotAssignable<DeepPartial<RespectArrayElements>>({
// this should error, undefined is not a valid type for list
list: [undefined, 'stable', 2],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard to say what was the problem and why "need to fix this" note is left here. As far as I can get, it all works as expected.

Comment on lines 12 to 7
* Shopify GIDs
*/
describe('composeGid', () => {
it('composes Gid using key and number id', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff is noisy, but it was so tempting to use describe() and it().

@mrazauskas
Copy link
Contributor Author

mrazauskas commented Feb 23, 2024

Hm.. Not sure what to do with Node.js 14. TSTyche is using AbortSignal.timeout() which is available from Node.js 16.14. If Node.js 14 support is a hard requirement, I can try reimplement AbortSignal.timeout(). The rest should work.

Apparently AbortController is experimental feature in Node.js 14. That’s more work, but still possible to reimplement. It is used only internally to handle --failFast. To be honest, I was thinking to add light reimplementation, because AbortSignal.any() would be useful too (add in Node.js 20.3 only). Also currently TypeScript supports Node.js ^14.17.0, so it makes sense to have similar capabilities.

@mrazauskas mrazauskas marked this pull request as ready for review February 23, 2024 06:58
@mrazauskas mrazauskas requested a review from a team as a code owner February 23, 2024 06:58
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Files are renamed because of two reasons: TSTyche suggest using .tst.ts suffix, because it is shorted and reflex the aim better (not executable test file); no need to have tstyche.config.json, less files in the root.

@mrazauskas
Copy link
Contributor Author

There are only unrelated failures in e2e. The rest works as expected.

This PR is ready for review. Or at least some feed back (;

@mrazauskas mrazauskas marked this pull request as draft March 1, 2024 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant