Production-Grade TypeScript

Production-Grade TypeScript Writing dtslint Assertions

Learning Paths:
Check out a free preview of the full Production-Grade TypeScript course:
The "Writing dtslint Assertions" Lesson is part of the full, Production-Grade TypeScript course featured in this preview video. Here's what you'd learn in this lesson:

Mike uses dtslint to test the project code against nightly TypeScript builds. Comments specific to dslint are added in the code specifying the minimum TypeScript version and annotating test assertions. Using the tsd library instead of dtslint eliminates the need to use special comments but can only test against a single TypeScript version.

Get Unlimited Access Now

Transcript from the "Writing dtslint Assertions" Lesson

>> And in our dtslint, we can say, all right, when I look for my lib, we can call it whatever you like. I wanna go to that dist, sorry, this will get me back to the root. This types, so we'll say my lib/*, reach into that disk types folder.

[00:00:26] All right, next, we're in this index DTS file. The thing we wanna add to the top of this is a special header. And this is a minimum TypeScript version. So one of the big value adds of this tool is it will download a bunch of different types of diversions for us and test them all sequentially.

[00:00:51] For a library this is super important, because this is how you make sure that you can maybe adopt new things or make fixes without breaking compatibility with the trailing edge of the the range of compiler versions you're aiming to support, right? If I wanna keep supporting 3.8 but we've got 4.0 and 4.1 someone opens a pull request.

[00:01:15] You don't want maintainers to have to think about all of the different features and when exactly did they land and what still works with 3.8. So this will check everything, all of the releases in sequence. And this is where you would, so this index DTS file needs to expose your types, right?

[00:01:47] You need to export stuff from this, that will then be available for testing. So I'm just gonna go to data and teams because this is where our interesting type lives. And here's the last thing we create here test.ts you can name this whatever you want. And this is where we could say import from.

[00:02:14] So we're gonna import our assertIsTypedArray and isIteam. So here we could say, In fact we could even do better than this. Let's not only get that team thing, let's get our types. So there we've got our ITeam coming through so you could see how we can expose whatever we need.

[00:02:42] And now we'll say const team which is an ITeam equals null, right? So this should break for TS config is set up properly. Let's restart a TypeScript server, I would expect this to break. There it is broken, perfect. So this is a unused variable. No, it's not assignable to type it.

[00:03:24] That's the important one, right? We can get rid of some of these other roles just to simplify this down. Like forget unused stuff. I guess it's already disabled. Just give it a fake usage, there we go. Okay, now we done to the key error. So what we wanna do here is add a special comment.

[00:03:51] ExpectError, so we're saying this better error. If this doesn't error, we're in trouble. It should be a bug. And let's see if this works. Let's see DTS lead is present, what's going on here?. Something in here is not making it happy. Maybe I need a black line there, nope.

[00:04:56] Let me just check the dtslint or sorry, the dtslint.json thing here. That looks right. And that is what I have. Maybe I just need my yarn. There we go. The difference between invoking something locally versus globally and volto took care of the correct version, but it might have been like the working directory or something that was that not playing real nice.

[00:05:35] So right now, behind the scenes, what's happening is I'm downloading a bunch of TypeScript versions. Let's see what's happening here. Test file should not use a relative import okay? I can get rid of this real easy. This is just, Or false is all you have to say. So normally you would shift things around so that you can consume these as if you're a user.

[00:06:10] This is just a simpler like quick and dirty way to demonstrate how the tool works. There we go, we're done, and then let's let's see if we can break our tests, so we see what happens there. So I expect an error but I want channels empty. I wanna make a valid one that should fail but in fact doesn't.

[00:06:44] This is an entirely valid team. All right, I've got my channels icon URL. Only ES LINT is complaining, only getting warnings. So let's see if it yells at us about this.
>> Level six.
>> Yeah, this might be a problem, we'll see. Thanks for the catch. We're already seeing the feedback though.

[00:07:30] And this is one advantage of having it based around the linter. Like, even though something broke later in the file, linters are designed to pick up all the problems in a file. So they're not strictly going to sort of stop at the first error and then kick out, right?

[00:07:47] So there we go, we have an error on line 4, and it's an error that occurred when testing TypeScript 4.1. It expected an error on this line and it found none. So this is great in terms of maintaining a compatibility range instead of just focusing on the version of TypeScript that you're using.

[00:08:09] So, obviously, this is a very convoluted setup process. And it's because this is a tool designed mostly for definitely typed, you can use it locally. There's a much easier to set up tool and it's gonna be like obviously what you're going to want to go for, but I wanna make sure you also have something that will protect you against that that nightly build which was included in the set of versions that were tested.

[00:08:36] So this is called tsd. Much, much, much more straightforward. Because it benefits from what we all learned about using DTS lint. So the idea here is you have real types that you can use to assert against. You're not using a special commenting language. You have real assertions. And the setup process is like dramatically easier.

[00:09:09] So we already have tsd installed. And we just need to create a file like believe like index.testd.ts. And let's see if we can do the same thing. So we'll get an ITeam. I'm just going to bring in like some very similar tests from what we already had these two here.

[00:09:45] And we'll just worry about like the bad one and the good one. So get rid of these funky comments. And from, This tsd library, we can have, expect. NotAssignable and expectAssignable. So here's how we would use each. You'd say expect, NotAssignable to ITeam null. And expectAssignable to ITeam and then pass that whole thing in.

[00:10:33] So obviously this is like much more friendly to read. Much more friendly to read. The only downside is, oops, I still need an index DTS here. I'm pretty sure this will work. The same one more or less. But without this top thing. We don't have the ability to test against multiple versions, that's all We should get some good feedback here.

[00:11:11] So that's supposedly our test just passed. Let's make sure they fail the way they're supposed to fail. There we go two errors. We're getting one error that we had an import that we didn't use and another that this was assignable. And the assertion said it shouldn't be, we're supposed to make sure this is not assignable, but it's assignable.

[00:11:46] Because we broke that test on purpose. So two different tools for testing. TSD has better assertions, it's easier to write your tests. They have a wider range of assertions. They have things in here like expect deprecated expect not not deprecated that use the js.@deprecated annotation, and you can make sure that nobody on deprecates things, parts of your API.

[00:12:14] Some really cool stuff, some deeper ways to assert and to describe the things you wanna test. The only thing it's missing is testing a range of TypeScript versions. But I think this is the path forward, it's just not quite there yet, which is why I still need both tools.