jest/no-conditional-in-test and type narrowing #10369
Answered
by
hi-ogawa
jamesarosen
asked this question in
Q&A
-
|
Given a function that uses the Result Pattern: type FooResult =
| { ok: true; value: number }
| { ok: false; error: Error }
function foo(n: number): FooResult {
return (Number.isFinite(n)) ? { ok: true, value: 2 * n + 1 } : { ok: false, error: new Error('n is infinite') }
} I want to write a test: describe('foo(3)', () => {
const result = foo(3)
expect(result.ok).toBe(true)
expect(result.value).toBe(7) // TS fails
})
describe('foo(∞)', () => {
const result = foo(Infinity)
expect(result.ok).toBe(false)
expect(result.error.message).toMatch(/infinite/) // TS fails
})TypeScript fails because neither describe('foo(3)', () => {
const result = foo(3)
expect(result.ok).toBe(true)
if (!result.ok) throw new Error('test error')
expect(result.value).toBe(7)
})
describe('foo(∞)', () => {
const result = foo(Infinity)
expect(result.ok).toBe(false)
if (result.ok) throw new Error('test error')
expect(result.error.message).toMatch(/infinite/)
})But that (a) requires doubling each such assertion and (b) violates We can fix it by making teaching TypeScript about the assertion: assertIsFalse(b: boolean): asserts b is true {
expect(b).toBe(false)
}
assertIsTrue(b: boolean): asserts b is true {
expect(b).toBe(true)
}
describe('foo(3)', () => {
const result = foo(3)
assertIsTrue(result.ok)
expect(result.value).toBe(7)
})
describe('foo(∞)', () => {
const result = foo(Infinity)
assertIsFalse(result.ok) // assertIsTrue(!result.ok) doesn't narrow
expect(result.error.message).toMatch(/infinite/)
})That seems... awkward. Does anyone have any ideas? |
Beta Was this translation helpful? Give feedback.
Answered by
hi-ogawa
May 17, 2026
Replies: 2 comments 1 reply
-
|
This is working https://stackblitz.com/edit/vitest-dev-vitest-bjrcixdf?file=test%2Frepro.test.ts import { expect, test } from 'vitest';
test('foo(3)', () => {
const result = foo(3);
expect.assert(result.ok);
expect(result.value).toBe(7);
});
test('foo(∞)', () => {
const result = foo(Infinity);
expect.assert(!result.ok);
expect(result.error.message).toMatch(/infinite/);
});
type FooResult = { ok: true; value: number } | { ok: false; error: Error };
function foo(n: number): FooResult {
return Number.isFinite(n)
? { ok: true, value: 2 * n + 1 }
: { ok: false, error: new Error('n is infinite') };
} |
Beta Was this translation helpful? Give feedback.
1 reply
Answer selected by
jamesarosen
This comment was marked as spam.
This comment was marked as spam.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is working https://stackblitz.com/edit/vitest-dev-vitest-bjrcixdf?file=test%2Frepro.test.ts