Open dotnetCarpenter opened 6 years ago
Link to JSDoc @augments / @extends: http://usejsdoc.org/tags-augments.html
After looking at the parser, it dawned on me that maybe the jest interfaces are wrongly weirdly typed.
expect.extend()
takes a jest.ExpectExtendMap
, which would mean that typescript should map my dynamic method to jest.ExpectExtendMap
to jest.Matchers<R>
, which of course is not possible.
But when I use @extends
, I am telling typescript that I am extending jest.Matchers
but what if I'm not?
What if I'm passing a type to the generic type jest.Matchers<R>
?
jest.Matchers<functorMatcher>
:
/**
* @class
*/
const functorMatcher = {
/**
* @method
* @param {*} actual The functor you want to test.
* @param {*} expected The functor you expect.
*/
functorToBe(actual, expected) {
const actualValue = getFunctorValue(actual)
const expectedValue = getFunctorValue(expected)
const pass = Object.is(actualValue, expectedValue)
return {
pass,
message () {
return `expected ${actualValue} of ${actual} to ${pass ? '' : 'not'} be ${expectedValue} of ${expected}`
}
}
}
}
expect.extend(functorMatcher)
But that doesn't work because what happens is that expect(just('foo'))
returns a type jest.Matchers<just>
and not a jest.Matchers<functorMatcher>
Or maybe I'm guessing too much and should just wait for someone, who really knows what's going on, to enlighten me.
Currently @augments
doesn't work for constructor functions, but that's not what going on here, I think. I think you want to augment the type of extends
. Typically Typescript has used merging for this in the past. In other words:
interface Expect {
// normal stuff in expect
}
declare const expect: Expect
// Filename: mine.js
interface Expect {
functorToBe(...): { pass, message }
}
I'm not sure of the best way to express this in jsdoc. Maybe @augments
is it, maybe it's not. Thoughts?
After a bit more thought, I think the core problem is that the statement that changes the type of expect
is a side-effecting function call, not a declaration. Typescript doesn’t have the ability to mutate types like that.
I think your best bet in the near term is to use a separate .d.ts file to express the type mutation as a type merge as I outlined above, although that may require some work on jest’s types if they are not amenable to merging already.
This not a satisfying solution for projects that want to be pure Javascript, however. Let’s keep this issue open to track the idea of a mutation-as-merge jsdoc tag.
Using vscode I can find a index.d.ts file (not sure where it originates from) that has a interface to Expect
.
/**
* The `expect` function is used every time you want to test a value.
* You will rarely call `expect` by itself.
*/
interface Expect {
/**
* The `expect` function is used every time you want to test a value.
* You will rarely call `expect` by itself.
*
* @param actual The value to apply matchers against.
*/
<T = any>(actual: T): Matchers<T>;
/**
* You can use `expect.extend` to add your own matchers to Jest.
*/
extend(obj: ExpectExtendMap): void;
// etc.
}
I would then add my own index.d.ts file with the following?
interface Expect {
functorToBe(...): { pass, message }
}
// or
interface Functor {
(value?: any): {
fmap: (f: function): Functor
}
}
interface Matchers<R> {
functorToBe(actual: Functor, expected: Functor): { pass: boolean, message: string }
}
Or I would define it in my test file?
Also not sure how to describe it without resorting to the type function
which does not seem to exist.
Take a look at Module Augmentation on https://www.typescriptlang.org/docs/handbook/declaration-merging.html. Your second idea of merging with Matchers is basically right, I think, since that's what is returned by expect
. Your index.d.ts would have to reference jest's index.d.ts via the name your import it as -- probably just 'jest'
.
Hmm.. this doesn't seem quite right. But I'll take it to SO and stop polluting this issue.
import { Matchers } from 'jest'
interface Functor<T> {
(value?: any): {
fmap: (f: value) => Functor<T>
}
}
interface Matchers<R> {
functorToBe(actual: Functor<T>, expected: Functor<T>): R
}
I wrote a simple extension of jest.Matchers but I can not get the typescript type checker to recognize my extension.
TypeScript Version: 3.0.1 (and 3.1.0-dev.20180825) The description below is for 3.0.1 - for 3.1.0-dev.20180825 all jest functions show errors, so I don't even think that the parser gets to my type at all.
Used via vscode version: 1.26.1
Search Terms: is:issue is:open jsdoc extends is:issue is:open jsdoc @augments is:issue is:open jsdoc "@augments"
I first asked this as a question on StackOverflow but after waiting a few days, I now suspect it is a bug in typescript's JSDoc implementation.
I also read the FAQ and found the link to jest but didn't find any information there either.
I'm using plain JavaScript and the code runs perfectly.
Code
Expected behavior:
expect().functorToBe
should be recognized as a function.Actual behavior: But in the line with
expect(just(1)).functorToBe(just(1))
, I get a red underline underfunctorToBe
and the following error message:I got
jest.Matchers
from writingexpect()
in vscode and looked at the description.Playground Link:
Related Issues: No.