add
function to add two numbers together, so that we can focus on the differences between JavaScript and TypeScript, rather than getting hung up on the details of this particular function.assert
from @ember/debug
. If you’re not familiar with it, you might want to take a look at its API docs! It’s a development-and-test-only helper that gets stripped from production builds, and is very helpful for this kind of thing!string
or undefined
or whatever else? We can drop that. Notice, too, that we can drop the assertion from our function definition, because the compiler will check this for us:as any
for your tests, so that you can test what happens when people feed bad data to your addon!add
function. Our setup will look a lot like it did in the JavaScript-only example—but with some extra type coercions along the way so that we can invoke it the way JavaScript-only users might.assert
in the body of the function. The inputs to our function here will get checked for us by any TypeScript users, but this way we are still doing the work of helping out our JavaScript users.as
operator to throw away what TypeScript knows about our code!TestContext
this
context of the tests, so that it can be used in the context of the test. For example, we might need to set up a User
type to pass into a Profile
component.User
and Profile
so that we have a good idea of what we’re testing.User
type is very simple, just an interface
:User
to pass into the test. With TypeScript on our side, we can even make sure that it actually matches up to the type we want to use!user
field doesn't exist on the TestContext
. Now, TypeScript does know that QUnit sets up that helpfully-named TestContext
—so a lot of the things we can do in tests work out of the box—but we haven’t told TypeScript that this
now has a user
property on it.this
in each test assertion includes the user
property, of type User
. We’ll start by importing the TestContext
defined by Ember’s test helpers, and extending it:this.user
in the test body.TestContext
and realize its an interface, you might be tempted to reach for declaration merging here. Don’t! If you do that, every single test in your entire application will now have a user: User
property on it!this.user
property was optional. That means that TypeScript won’t complain if you do this.user
before assigning to it. Second, every test in our module gets the same Context
. Depending on what you’re doing, that may be fine, but you may end up needing to define multiple distinct test context extensions. If you do end up needing to define a bunch of different test context extension, that may be a sign that this particular set of tests is doing too much. That in turn is probably a sign that this particular component is doing too much!