Making Jasmine and TypeScript play nicely together

Chris Rowe
2 min readOct 3, 2016

My love hate relationship with TypeScript is currently in a love phase. This was recently made concrete following Angular 2’s NgModule/TestBed addition and my subsequent huge and yet relatively painless refactor.

However, occasionally something happens to make me reevaluate my feelings towards TypeScript. The compiler errors I found when running Jasmine unit tests were one such time.

TypeScript lovers will know that the first step to remove most TypeScript compiler errors is to get the latest definition file for the offending library. Since TypeScript 2.0 this can be as simple as:

npm install @types/jasmine

Matchers

The first real error that TypeScript threw at me was when I added a custom matcher.

Property ‘toHaveText’ does not exist on type ‘Matchers’.

Thankfully TypeScript is clever enough to merge a custom definition with the one installed from NPM. This means we can easily declare a new namespace for jasmine with our custom matchers added to it.

declare namespace jasmine {
interface Matchers {
toHaveText(expected: string): boolean;
}
}

I put this definition alongside the custom matcher code which helps me to keep the two in sync.

Spies

Quite often we want to spy on a function to see if it has been executed by our test. We may also want to access properties and methods on that spy, for example to see how many times it was called, e.g.

spyOn(component.searchChange, 'emit');
// do something then...
expect(component.searchChange.emit.calls.count()).toEqual(1);

The problem here is that by using Jasmine’s spyOn method we have effectively monkey patched our searchChange method in a way that the TypeScript compiler is unable to understand, and we get the following error.

Property ‘calls’ does not exist on type ‘(value?: any) => void’.

I managed to get around this problem when I realised that the spyOn method also returned an instance of the spy that it created. And if we use this reference to the spy going forward the TypeScript compiler is once again happy. As a bonus, I think this makes the code more readable.

const searchChangeEmitSpy = spyOn(component.searchChange, 'emit');
// do something then...
expect(searchChangeEmitSpy.calls.count()).toEqual(1);

The great news is that now that we have removed some unnecessary errors, we're more likely to spot a real one… and the love blossoms.

--

--