我正在尝试在Typescript中为Jest添加自定义匹配器。这样可以正常工作,但我无法获取Typescript来识别扩展的Matchers
。
myMatcher.ts
export default function myMatcher (this: jest.MatcherUtils, received: any, expected: any): { pass: boolean; message (): string; } {
const pass = received === expected;
return {
pass: pass,
message: () => `expected ${pass ? '!' : '='}==`,
}
}
myMatcher.d.ts
declare namespace jest {
interface Matchers {
myMatcher (expected: any): boolean;
}
}
someTest.ts
import myMatcher from './myMatcher';
expect.extend({
myMatcher,
})
it('should work', () => {
expect('str').myMatcher('str');
})
tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"moduleResolution": "node",
"module": "es6",
"target": "es5",
"lib": [
"es7",
"dom"
]
},
"types": [
"jest"
],
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"doc",
"**/__mocks__/*",
"**/__tests__/*"
]
}
在someTests.ts中,我收到错误
error TS2339: Property 'myMatcher' does not exist on type 'Matchers'
我已多次阅读Microsoft文档,但我无法弄清楚如何使用全局可用类型(未导出)进行命名空间合并。
将它放在来自jest的index.d.ts中可以正常工作,但对于快速变化的代码库以及由多方扩展的类而言,它不是一个很好的解决方案。
答案 0 :(得分:16)
好的,这里有一些问题
当源文件(.ts
或.tsx
)文件和声明文件(.d.ts
)文件都是模块解析的候选者时,就像这里的情况一样,编译器将解析源文件。
您可能有两个文件,因为您要导出值并修改全局对象jest
的类型。但是,您不需要两个文件,因为TypeScript具有用于从模块中扩充全局范围的特定构造。也就是说,您只需要以下.ts
文件
<强> myMatcher.ts 强>
// use declare global within a module to introduce or augment a global declaration.
declare global {
namespace jest {
interface Matchers {
myMatcher: typeof myMatcher;
}
}
}
export default function myMatcher<T>(this: jest.MatcherUtils, received: T, expected: T) {
const pass = received === expected;
return {
pass,
message: () => `expected ${pass ? '!' : '='}==`
};
}
也就是说,如果您遇到这种情况,最好在同一个文件中执行全局变异和全局类型扩充。鉴于此,我会考虑将其重写如下
<强> myMatcher.ts 强>
// ensure this is parsed as a module.
export {};
declare global {
namespace jest {
interface Matchers {
myMatcher: typeof myMatcher;
}
}
}
function myMatcher<T>(this: jest.MatcherUtils, received: T, expected: T) {
const pass = received === expected;
return {
pass,
message: () => `expected ${pass ? '!' : '='}==`
};
}
expect.extend({
myMatcher
});
<强> someTest.ts 强>
import './myMatcher';
it('should work', () => {
expect('str').myMatcher('str');
});
答案 1 :(得分:3)
一个简单的方法是:
<强> customMatchers.ts 强>
declare global {
namespace jest {
interface Matchers<R> {
// add any of your custom matchers here
toBeDivisibleBy: (argument: number) => {};
}
}
}
// this will extend the expect with a custom matcher
expect.extend({
toBeDivisibleBy(received: number, argument: number) {
const pass = received % argument === 0;
if (pass) {
return {
message: () => `expected ${received} not to be divisible by ${argument}`,
pass: true
};
} else {
return {
message: () => `expected ${received} to be divisible by ${argument}`,
pass: false
};
}
}
});
<强> my.spec.ts 强>
import "path/to/customMatchers";
test('even and odd numbers', () => {
expect(100).toBeDivisibleBy(2);
expect(101).not.toBeDivisibleBy(2);
});
答案 2 :(得分:0)
@AluanHaddad的回答几乎是正确的,只有几种类型。 这一项有效:
export {};
declare global {
namespace jest {
interface Matchers<R> {
myMatcher: (received: string) => R;
}
}
}
function myMatcher<T>(this: jest.MatcherUtils, received: string, expected: string): jest.CustomMatcherResult {
const pass = received === expected;
return {
pass,
message: (): string => `expected ${received} to be ${expected}`,
}
}
expect.extend({
myMatcher,
});
有关真实示例,请参见https://github.com/Quantum-Game/quantum-tensors/blob/master/tests/customMatchers.ts(并且测试实际通过:https://travis-ci.com/Quantum-Game/quantum-tensors)。
答案 3 :(得分:0)
在 "@types/testing-library__jest-dom"
中将 types
添加到 tsconfig.json
为我解决了这个问题
// tsconfig.json
"types": [
"node",
"jest",
"@types/testing-library__jest-dom"
],
也请参阅此答案Property 'toBeInTheDocument' does not exist on type 'Matchers<any>'